Forum Rule: Always post complete source code & details to reproduce any issue!
Page 3 of 4 FirstFirst 1 2 3 4 LastLast
Results 51 to 75 of 95

Thread: EEPROM writing on T_3.6 in HSRUN mode

  1. #51
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700

    Blink Simple Sample of HSRUN EEPROM WRITE

    This is a Blink Simple Sample of writing the EEPROM - even on the T_3.6 while over 120 MHz. The prior code shows evolving test code to develop and see it work.

    Code:
    // #include "EESpeedDHR.h" // THIS FILE
    
    // ------------------- COPY BELOW THIS TO YOUR CODE
    /*
       The following allows writing to EEPROM at HSRUN speeds on T_3.6,
       it compiles out when not T_3.6 or under HSRUN speeds
       USAGE: 
        HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
          EEPROM[ 0 ] = 5;   // YOUR CODE HERE
        }
    */
    uint8_t DropHSRUN( uint8_t DropState ) {
      if (DropState) {
        Serial.flush();   // make sure nothing queued to send
        __disable_irq( ); // Turn off interrupts for the DURATION !!!!
        SMC_PMCTRL = SMC_PMCTRL_RUNM(0); // exit HSRUN mode
        while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) ; // wait for !HSRUN
      }
      else {
        SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
        while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) delay(1); // wait for HSRUN
        __enable_irq( ); // Restore interrupts only when HSRUN restored
      }
      return DropState; // macro needs 1 on drop call and 0 on raise call to process
    }
    
    #define TYPE uint8_t
    #if F_CPU > 120000000 && defined(__MK66FX1M0__)
    #define HSRUN_DROP_BLOCK() for (TYPE __ToDo=DropHSRUN(1); __ToDo; __ToDo=DropHSRUN(0))
    #else
    #define HSRUN_DROP_BLOCK() for ( TYPE __ToDo=1; __ToDo; __ToDo=0)
    #endif
    // ------------------- COPY ABOVE THIS TO YOUR CODE
    Code:
    #include <EEPROM.h>
    #include "EESpeedDHR.h"
    
    void setup() {
      HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
        EEPROM[ 0 ] = EEPROM[ 0 ] + 1;
      }
      pinMode(LED_BUILTIN, OUTPUT);
      Serial.begin(57600);
      while (!Serial && (millis ()  <= 8000));
      Serial.print(" __ EEPROM[ 0 ] =");    Serial.println(EEPROM[ 0 ]);
      digitalWrite(LED_BUILTIN, HIGH);   // turn the LED_BUILTIN on (HIGH is the voltage level)
    
      // put your setup code here, to run once:
    }
    
    int ii = 0;
    void loop() {
      HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
        EEPROM[ ii ] = EEPROM[ ii ] + 1;
      }
      Serial.print(" __ EEPROM[ "); Serial.print(ii); Serial.print(" ] =");    Serial.println(EEPROM[ ii ]);
      delay(1000);
      digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
      if ( ++ii > E2END / 2) ii = 0;
      // put your main code here, to run repeatedly:
    }

  2. #52
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,421
    For the fun of it, was wondering what would happen to hardware Serial during this, so I hacked up your program a little:
    Code:
    #include <EEPROM.h>
    #include "EESpeedDHR.h"
    
    void setup() {
      HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
        EEPROM[ 0 ] = EEPROM[ 0 ] + 1;
      }
      pinMode(LED_BUILTIN, OUTPUT);
      Serial.begin(57600);
      Serial1.begin(115200);
      pinMode(2, OUTPUT);
      digitalWrite(2, LOW);
      while (!Serial && (millis ()  <= 8000));
      Serial.print(" __ EEPROM[ 0 ] =");    Serial.println(EEPROM[ 0 ]);
      digitalWrite(LED_BUILTIN, HIGH);   // turn the LED_BUILTIN on (HIGH is the voltage level)
    
      // put your setup code here, to run once:
    }
    
    int ii = 0;
    void loop() {
      // Wait for some input from Serial
      Serial.println("Waiting for input");
      while (Serial.read() == -1) ;
      while (Serial.read() != -1) ; // eat the rest of the characters
      Serial1.print("123456780!01234567890!!1234567890");
      digitalWrite(2, HIGH);
      HSRUN_DROP_BLOCK(  ) { // DO NO I/O in this block
        EEPROM[ ii ] = EEPROM[ ii ] + 1;
      }
      digitalWrite(2, LOW);
      Serial.print(" __ EEPROM[ "); Serial.print(ii); Serial.print(" ] =");    Serial.println(EEPROM[ ii ]);
      delay(1000);
      digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
      if ( ++ii > E2END / 2) ii = 0;
      // put your main code here, to run repeatedly:
    }
    I mainly added having the code wait for some input before running the next loop. Then doing a Serial1, print of some data, then set pin 2 high, run your code, and then set pin 2 low again. Then I ran it with Logic Analyzer hooked up.

    Click image for larger version. 

Name:	screenshot.jpg 
Views:	67 
Size:	46.7 KB 
ID:	8211

    Looks like the Serial output went through without problem

    Edit: Forgot to mention I was running at 216mhz

    Kurt
    Last edited by KurtE; 09-17-2016 at 01:50 PM.

  3. #53
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    Cool, it is nice the _BLOCK is running without altering any core frequencies. Only risk to data is losing interrupts ( that doesn't stop the DMA or FIFO hardware though right? ) and having stuff complete or fill up without interrupt response, that and the fact that HSRUN is off at high speed and if the processor is working hard that lowered voltage could cause some fault for whatever reason the higher voltage logic was seen to be needed.

    FrankB's full screen buffer DMA ILI9341 code might be a good test. Your test above where a second Teensy was monitoring the Serial1.print("123456780!01234567890!!1234567890") ; and echoing it back might show loss - especially at higher baud with no flow control. The 'Blink Simple sample' is only writing a single value and the _BLOCK code is under __disable_irq( ); for <2 ms [ most of it from this line :: while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) delay(1); // wait for HSRUN ], but the update of ~3,800 EEPROM addresses takes about 450 ms. These times are printed in verbose mode with the prior RTC sample.

    Maybe I should add a yield() before the Serial.flush() at the _BLOCK start? For those using SerialEvent - that would get the incoming buffers empty? Of course the more of that put in the _BLOCK code the longer it takes, but the interrupts are still running then. This will have to be used infrequently and with care to have the Teensy not lose data. The USB is surviving without loss AFAIK because it is robust - I minimized output before the _BLOCK code, and did a .flush().

    <edit>Something odd with elapsedMillis and my effort to use it in FASTLED_CYCLON:: . . . it is me - I'm resolving that
    Last edited by defragster; 09-17-2016 at 07:40 PM.

  4. #54
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    Edited EEPROM.c, this doesn't cover EEPROM.cpp style usage (TODO) - but it seems to work in my prior test code?

    You can use the _BLOCK scheme - but entering if HSRUN dropped will ignore this code. To use the same code I just did this comment and replace:
    Code:
    //#if F_CPU > 120000000 && defined(__MK66FX1M0__)
    #if F_CPU > 320000000 && defined(__MK66FX1M0__)
    
    No safety net (no USB purge and no delay(1) while waiting on HSRUN to restore) - but if HSRUN active before EEPROM write - drop int's and HSRUN - do the write - if dropped then raise HSRUN and int's - return.
    Code:
    #if F_CPU > 120000000 && defined(__MK66FX1M0__)
    uint8_t restore_hsrun = 0;
    static void hsrun_off(void)
    {
    	if (SMC_PMSTAT == SMC_PMSTAT_HSRUN) {
    		__disable_irq( ); // Turn off interrupts for the DURATION !!!!
    		SMC_PMCTRL = SMC_PMCTRL_RUNM(0); // exit HSRUN mode
    		while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) ; // wait for !HSRUN
    		restore_hsrun = 1;
    	}
    }
    
    static void hsrun_on(void)
    {
    	if (restore_hsrun) {
    	    SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
    	    while (SMC_PMSTAT != SMC_PMSTAT_HSRUN); // wait for HSRUN
    	    restore_hsrun = 0;
    	    __enable_irq( ); // Restore interrupts only when HSRUN restored	}
    	}
    }
    #else
    #define hsrun_off()
    #define hsrun_on()
    #endif
    Sample edit:
    Code:
    void eeprom_write_byte(uint8_t *addr, uint8_t value)
    {
    	uint32_t offset = (uint32_t)addr;
    
    	if (offset >= EEPROM_SIZE) return;
    	hsrun_off();
    	if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
    	if (FlexRAM[offset] != value) {
    		uint8_t stat = FTFL_FSTAT & 0x70;
    		if (stat) FTFL_FSTAT = stat;
    		FlexRAM[offset] = value;
    		flexram_wait();
    	}
    	hsrun_on();
    }
    replaced "C:\arduino_16_11\hardware\teensy\avr\cores\teensy 3\eeprom.c" with:: eeprom.c
    **NOTE - this CORE file will only recompile if you change to T_LC and VERIFY and then back to T_3.6 ( over 120 MHz to have it work)
    **NOTE - eeprom.c won't recompile on CHANGE of file timestamp or CPU speed

  5. #55
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    The above code is working for the testing done - I replaced the _irq() calls with these to preserve the interrupt state in the event there is an EEPROM write when interrupts are already off so they aren't blindly enabled:
    Code:
    static volatile uint16_t c_intcnt = 0;
    void c_enable_irq( void );
    void c_disable_irq( void );
    static __inline__ uint32_t __get_primask(void) \
    { uint32_t primask = 0; \
      __asm__ volatile ("MRS %[result], PRIMASK\n\t":[result]"=r"(primask)::); \
      return primask; } // returns 0 if interrupts enabled, 1 if disabled
    void c_enable_irq( void ){
    	if ( c_intcnt ) {
    		c_intcnt--;
    		if ( !c_intcnt )
    			__enable_irq( );
    	}
    }
    void c_disable_irq( void ){
    	if ( !__get_primask() ) { // Returns 0 if they are enabled, or non-zero if disabled 
    		c_intcnt++;
    		__disable_irq( );
    	}
    }
    based on - or in spite of this thread.
    Last edited by defragster; 09-21-2016 at 09:05 AM.

  6. #56

  7. #57
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    Here in a zip are my two pull requests pending for CORES. First to get serial number reported on USB for a T_3.6 in HSRUN/over 120 MHz. The second is the modifications I made to EEPROM.c that (transparently) allow writes under the same T_3.6 HSRUN conditions.

    SEE Post #68 { included CORES files are modified from the current TeensyDuino 1.31b1 }
    Pull request updated :: PaulStoffregen/cores/pull/177

    Also Included in this ZIP are two sketches::
    > SerEEpromSysTick.ino :: A complete sketch showing both fixes working - the USB serial number will be reported and it works in the sketch as well.

    This is shown on a build without these changes applied:
    F_CPU =240000000 Serial # =0
    Prints each 10 seconds - one value updated each second
    USER INPUT:: 'z' is ZERO EEPROM :: 'p' is INCREMENT EEPROM
    last:: 255 255 255 255 255 255 255 255 255 255
    ------- EE_index=0 (compare next to following last for +=1)
    next:: 11 11 10 4 4 3 3 3 1 1

    FAIL ------- EE_index=0
    FAIL ------- EEPROM[ EE_index } =11
    FAIL ------- EEPROM[ EE_index } NOT ==12
    Then you'll see a PANIC FLASH on the LED.

    > SerEEpromSysTickMin.ino :: As above but Minimal version with only required void systick_isr() and supporting code just for EEPROM update each second, does not attempt to show 'Serial #' as above. You can put this in the sketch of your choosing to see if EEPROM writes with HSRUN dropping cause any trouble.

    NOTES:
    > ZERO is efficient writing fewer blocks of 256 bytes, while INCREMENT does cell by cell updates.
    > First line 'last' is bogus at the start of test as it wraps before the start of EEPROM and those values are not yet addressed

    BONUS: Here is output at 120 MHz {using the 1.31b1 code- and below that at 180 MHz with the edited code for HSRUN::
    F_CPU =120000000 Serial # =2272860
    Prints each 10 seconds - one value updated each second
    USER INPUT:: 'z' is ZERO EEPROM :: 'p' is INCREMENT EEPROM
    last:: 255 255 255 255 255 255 255 255 255 255
    ------- EE_index=0 (compare next to following last for +=1)
    next:: 12 12 11 5 5 4 4 4 2 2
    last:: 13 13 12 6 6 5 5 5 3 3
    ------- EE_index=10 (compare next to following last for +=1)
    next:: 2 2 2 2 2 2 1 1 1 1
    last:: 3 3 3 3 3 3 2 2 2 2
    ------- EE_index=20 (compare next to following last for +=1)
    next:: 1 1 1 0 0 0 0 0 0 0
    FULL INCREMENT in microseconds=2190762
    last:: 0 0 0 0 0 0 0 0 0 255
    ------- EE_index=0 (compare next to following last for +=1)
    next:: 15 15 13 7 7 6 6 6 4 4
    last:: 16 16 14 8 8 7 7 7 5 5
    ------- EE_index=10 (compare next to following last for +=1)
    next:: 4 4 4 4 4 4 3 3 3 3
    last:: 5 5 5 5 5 5 4 4 4 4
    ------- EE_index=20 (compare next to following last for +=1)
    next:: 3 3 3 1 1 1 1 1 1 1
    FULL ZERO in microseconds=22705
    last:: 0 0 0 0 0 0 0 0 0 0
    ------- EE_index=0 (compare next to following last for +=1)
    next:: 0 0 0 0 0 0 0 0 0 0
    last:: 1 1 1 1 1 1 1 1 1 1
    And at 180 MHz - note the ZERO and INCREMENT times are affected existing values where same values are not rewritten and time is minimal - see double zero below. The INCREMENT is worst case method writing all 4096 bytes with change one at a time { below is 2.5 seconds I have seen 3.12 seconds } - but that is better than no writes at all - and there are more efficient ways to update.
    UPDATED: I just added a "P" block increment { upper case 'P' for PLUS } that runs in under 20 milliseconds, so keeping a RAM copy could be done in a full block update where not everything changes even faster!
    F_CPU =180000000 Serial # =2272860
    Prints each 10 seconds - one value updated each second
    USER INPUT:: 'z' is ZERO EEPROM :: 'p' is INCREMENT EEPROM
    last:: 2 2 2 2 2 2 2 2 2 2
    ------- EE_index=10 (compare next to following last for +=1)
    next:: 1 1 1 1 1 1 1 1 1 1
    last:: 2 2 2 2 2 2 2 2 2 2
    ------- EE_index=20 (compare next to following last for +=1)
    next:: 1 1 1 1 1 1 1 1 1 1
    last:: 2 2 2 2 2 2 2 2 2 2
    ------- EE_index=30 (compare next to following last for +=1)
    next:: 1 1 1 1 1 1 1 1 1 1
    FULL 'block' INCREMENT in microseconds=17575
    last:: 1 1 1 1 1 1 1 1 1 1
    ------- EE_index=0 (compare next to following last for +=1)
    next:: 3 3 3 3 3 3 3 3 3 3
    last:: 4 4 4 4 4 4 4 4 4 4
    ------- EE_index=10 (compare next to following last for +=1)
    next:: 3 3 3 3 3 3 3 3 3 3
    FULL INCREMENT in microseconds=3130338
    last:: 2 2 2 2 2 2 2 2 2 1
    ------- EE_index=0 (compare next to following last for +=1)
    next:: 6 6 6 5 5 5 5 5 5 5
    last:: 7 7 7 6 6 6 6 6 6 6
    ------- EE_index=10 (compare next to following last for +=1)
    next:: 5 5 4 4 4 4 4 4 4 4
    FULL ZERO in microseconds=16030
    last:: 0 0 0 0 0 0 0 0 0 0
    ------- EE_index=0 (compare next to following last for +=1)
    next:: 0 0 0 0 0 0 0 0 0 0
    FULL ZERO in microseconds=1168
    last:: 0 0 0 0 0 0 0 0 0 0
    ------- EE_index=0 (compare next to following last for +=1)
    next:: 0 0 0 0 0 0 0 0 0 0
    For the BLOCK INCREMENT code I did not update the 'help' print in the zipped code:
    Serial.println( " USER INPUT:: 'z' is ZERO EEPROM :: 'p' is INCREMENT EEPROM :: 'P' is FAST BLOCK INCREMENT EEPROM" );
    Last edited by defragster; 10-03-2016 at 08:49 AM.

  8. #58
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    5,679
    The code looks pretty good - and the idea ( switch HSRUN ) is superb ;-)

    It works perfect on my both T3.6 (beta & pre-production) - BUT: We should test this on many 3.6 as possible - and, perhaps, place a #warning in the code ?

  9. #59
    Hi Guys - I have been trying to keep up on this issue but there is a lot of details and a lot of posts about it. I have some confusion about the current state of this issue so I have some basic questions about doing EEPROM writes on a T3.6 since my code saves a lot of config data in EEPROM.

    1) Do EEPROM writes on T3.6 not work out of the box? (It sounds like the answer to this is yes but well, that just seems surprising so I want to really make sure I understand correctly...)
    2) If yes then what is my simplest path to get this working? (ie which patch should I used)
    3) It sounds like these patches have side effects that may be unpleasant like usb hardware not working after a eeprom write or unreliability etc., what is the current state of this?

    I guess I am just looking for a layman's explanation that does not assume I know the inner workings of the ARM processor so I can have confidence I can use EEPROM on T3.6 and move on to other issues.

    Thanks so much!
    Brent

  10. #60
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    5,679
    1) It does work, but the chip prevents writing to the EEprom in so-called "HSRUN"-Mode which is enabled above 120MHz CPU-Speed.
    So..the answer is: Official, at the moment, you can use it up to 120MHz "out of the box", but not above. I don't know what Pauls plans are..but i'm sure he will find a solution or just uses Defragster's
    2) Try the zip-file from Post #57 (replace the original file)
    3) I've not noticed side-effects (but did not read all posts in this thread - i never use the eeprom (only for this test..) ), but i'm sure Defragster can tell more. It disables the Interrupts a little longer than usual.

    But, please note, this workaround is still a bit in "experimental" state.
    Last edited by Frank B; 10-01-2016 at 06:53 PM.

  11. #61
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    Brent: As I understand it :: The T_3.6 was built with a power boost OC feature from the factory that is spec'd for use when the processor runs over 120 MHz. The chip is spec'd for normal use at 180 MHz. Up to 120 MHz the internal voltage is in a normal range and the EEPROM portions of the chip can be read and written without issue. Once it is set to HSRUN (High Speed Run) over 120 the EEPROM can be read normally, but any writes are internally blocked because the over voltage state was determined to be 'unsafe' by the manufacturer. {also certain other reads like the serial number from the one time write area are blocked }

    This thread evolved through three states to allow writes:
    1> drop the speed and write, then restore the speed,
    2> Create a _BLOCK area where interrupts are disabled to assure no other code runs - and drop the processor speed and drop the OC HSRUN voltage level and perform the writes, which worked, but unless in the _BLOCK, the writes failed, and in transitioning the speed certain other system elements based on timing could be confused if I/O occurred and device interface might need to be restored - like USB - and any timers.

    3> This third and final/current version [ thanks to Frank ] presented in post #57 (and just before) - said just drop HSRUN and try it. Interrupts are disabled so no other code can run at this time as there may be certain instructions or operations that would fail at high speed without the adjusted internal voltage. For this I ended up integrating the adjusted code directly within the EEPROM write code when compiled on the T_3.6 over 120 MHz. With this adjustment the interrupts and HSRUN state and voltage is dropped only long enough to transfer data to the EEPROM when no other code is executed. I have tested enough variations I don't see the low power operation to be a stability problem. I have done some many passes and edits to EEPROM for days in a conservative above normal but not abusive manner. The only way to be sure this doesn't have long term effects would be to attempt some 10,000's of thousands of abusive high speed repetitive updates and see it there is any sign of early failure from lingering High Voltage as there is no significant delay in this code when dropping from HSRUN. A simple but time consuming safety margin could be added as follows:

    Code:
    static void hsrun_off(void)
    {
    	if (SMC_PMSTAT == SMC_PMSTAT_HSRUN) {
    		c_disable_irq( ); // Turn off interrupts for the DURATION !!!!
    		SMC_PMCTRL = SMC_PMCTRL_RUNM(0); // exit HSRUN mode
    		while (SMC_PMSTAT == SMC_PMSTAT_HSRUN) delayMicroseconds(10); // wait for !HSRUN  - a variable delay if the HSRUN exit takes any time
    		// Adding some delay here would assure the voltage level actually drops maybe some small fixed delayMicroseconds(10);
    		restore_hsrun = 1;
    	}
    }
    In FULL 'block' INCREMENT in microseconds=17575 above that is 16 calls for block updates [ it could be done in fewer larger blocks ]. Each of those calls would average just over 1.1 milliseconds. Where EVERY byte was changed. So adding 100 microseconds would be 10% and might be a good safety margin? Single BYTE changes look to average760 us - at 3.11 seconds for 4096 writes. So the overhead is high - but it is the similar in the 120 MHz case shown above where this code is not done. 537 us for single updates but 1419 us for the block zeros.
    Last edited by defragster; 10-01-2016 at 09:28 PM.

  12. #62
    Thanks for the explanations Frank and Defragster! I appreciate the help.

    Brent

  13. #63
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    Good, and yes thanks Frank. I've not used the EEprom for much of anything either - but it seemed like a hole in the T_3.6 not being able to use it. So I've spent more time with it doing this thread than before or probably ever again.

    I was just thinking out loud p #61 - now it seems I should repost and update the pull requests with at least a few us delays before rushing in to write. If the voltage is still a bit hot for any reason it could be causing premature EEPROM aging. And the internals of the timing and internal protection are an unknown - HSRUN may not drop until voltages do - they may drop really fast - or the EEPROM hardware access may monitor that - or maybe neither is there as a safety net and a few usecs lost is better than no usage or a toasted chip - when it just takes a bit more time when writes are blocked efficiently. The 4096 calls for 3+ seconds would be prohibitive versus 16 or 32 calls of reasonable structure size done as a '.put'

    The only delays I used before was coming out before enabling interrupts in the state '2' code as the instant the interrupt enable happen the processor was wisked away before the USB was ready it seemed. That isn't so much an issue in state '3' code where no clocks change - as long as the needed voltage is there to run properly.

    Just added include of core_pins.h to get delayMicroseconds - put in some small 20 us delays and not seeing the time extend. Almost like the waits I added were being absorbed or taken off the time it was waiting already?

    For the 4096 write case when I added 40+ us that would add 164 ms to the total time - but interrupts come and go 4K times in 3.2 seconds so no time may be lost - each write averages 782 us. BLOCK writes back to back are 17ms and 1.8ms so 9 times faster when no write is needed.

    Looking at 144 and 120 side by side it is odd - same sketch should be the same updates:

    The block writes at 144 are somehow 42 times faster - even with the longer delays. And the 4096 individual increments are 6% slower as expected.

  14. #64
    It would probably be worth it to have a new API to write an array of bytes to EEPROM so that the overhead of going out and back in HSRUN would be less...
    Last edited by iambrentiam; 10-02-2016 at 05:19 AM.

  15. #65
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    This exists - it is what I use in the 'block' or '.put' writes. It was added to Arduino late last year.

    Here is .put ref :: www.arduino.cc/en/Reference/EEPROMPut

    You point to any compile time fixed structure or data type and it is read/get or written/put in one operation.

    This code from sample above write 16 groups of 256 zero bytes to fill all of EEPROM with zeros.
    Code:
    for ( int ii = 0; ii < E2END; ii += sizeof( buf2 )) EEPROM.put( ii, buf2 );

  16. #66
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,256

    Cool

    Quote Originally Posted by iambrentiam View Post
    It would probably be worth it have a new API to write an array of bytes to EEPROM so that the overhead of going out and back in HSRUN would be less...
    Looking at EEPROM.h you will see there are put and get templates to facilitate writing and reading a series of bytes to the saved storage:


    Now all we have to do is get people to use it. I must admit, I wasn't aware that these functions existed, until I looked at the files for this reply.

    It looks like the new version was added by Christopher Andrews in 2015 (see the last link above for the announcement).

    I recall asking Paul to publish the earlier teensy interface that had multiple byte support as an ARM only function when the LC came out (where you want to be sparing about EEPROM access), and he was hesitant to do so, since the core Arduino libraries at the time only did single byte read and write (this was probably in 2013 or 2014, when I was writing my private interface that sits on top of EEPROM).
    Last edited by MichaelMeissner; 10-02-2016 at 05:21 AM.

  17. #67
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    CURRENT CODE - SerEEpromSysTick.zip :: two CORES files from TeensyDuino 1.31b1 that use the same techniques to:
    >> usv_desc.c :: acquire Serial # for use with USB and user sketch
    >> eeprom.c :: drop from HSRUN state at any speed over 120 MHz, perform requested EEPROM write, restore HSRUN state and return.

    SEE FOLLOWING POST FOR UPDATE DETAILS

    Funny - Bing searches for Arduino ref data now have .cc and .org both in the results. I just saw this yesterday for the first time.

    This reads all 4096 EEPROM bytes to RAM:
    Code:
        char bufall2[1 + E2END];
        EEPROM.get( 0, bufall2 );
    Adding error checking after ZERO and INCREMENT - read all before and after and comparing the two, so I have two 4KB buffer I read bufall1 - update - read buffall2 and compare in RAM. I detect no errors above 120 MHz - but I do see a couple at 120 MHz - because all this is done while the systick counter isr is updating a value once per second. Some of the writes have been ordered top down to over write this - so a couple of errors in line with the time taken only shows it is slower and systick is getting updated.

    Just for reference I did these timing runs - This is with a 40 us wait on each call that drops HSRUN to write changed data ( plus some 2 us waits in what were 'empty while waits' watching for HSRUN to change ) the ODD thing is how SLOW the block writes are at 120 MHz???? Seeing those is why I added the FULL EEPROM read and compare and also the overall total time that includes the two block reads and other test setup and they agreed. The last "144 50w" column I put the wait from 40 to 50 us used in the other tests, and "240 70w" column waits 70 after each drop of HSRUN before starting - oddly some .put loops are faster and of course the 4096 count single writes got slowed. I added a 128 byte put to see if the average time would drop under a second (since the interrupts are off that long) and it is not a win, just twice as many calls::

    Code:
    CPU SPEED	120 	240 40w	240 70w	144 40w	144 50w
    256 .put ZERO	755965	16261	15492	15374	15971
    256 .put ZERO	1033	1869	2287	1899	2041
    256 .put ZERO	1103	1767	2319	1870	2050
    byte INC	3018428	3212295	3324138	3223428	3240725
    byte INC	3030755	3209799	3343121	3219856	3256964
    256 .put INC	756365	15726	15932	17326	16954
    256 .put INC	754374	15736	15917	16898	15499
    128 .put INC	752566	31604	32660	32303	32542
    128 .put INC	756510	31777	32500	33686	33216

    As above what this shows is that even if we could drop to 120 MHz safely [we can't] - the time spent there would be generally longer! So if adding a bit of buffer time can be faster than 120 MHz it is better to have some margin? I've gone from NONE to 70us per call and only the single byte writes suffer measurably - and somehow the time for .put blocks seems within the margin of error. The only thing I can see that explains this is if the processor does have safety net delays for high voltage writes?
    Last edited by defragster; 10-03-2016 at 08:35 AM.

  18. #68
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    PULL REQUEST UPDATED :: PaulStoffregen/cores/pull/177

    CURRENT CODE - SerEEpromSysTick.zip
    Two CORES files from TeensyDuino 1.31b1 that use the same techniques to:
    >> usv_desc.c :: acquire Serial # for use with USB and user sketch
    >> eeprom.c :: drop from HSRUN state at any speed over 120 MHz, perform requested EEPROM write, restore HSRUN state and return.

    > updated to put in delayMicroseconds(100) on leaving HSRUN - this is preventative speculation to make sure !HSRUN stabilizes internally - though oddly added time had to get to 100us before it added noticeably to single byte writes - and even then the times for fewer and larger blocks are not always slower? - it really seems like the time to write EEPROM is gated on the CPU getting to the proper state before writing to EEPROM - so it is much more efficient to do it on larger blocks! Most oddly is how SLOW the write is at 120 MHZ shown above.

    Sample Sketch SerEEpromSysTick::
    > New 'Features':: "'z' BLOCK ZERO : 's' SHOW val : 'I' is 128 INC : 'p' is INC : 'P' is 256 INC :: 'd' DWORD ZERO :: 'w' WORD 0xFFFF :: "
    • 'z' BLOCK ZERO : zero all eeprom with 256 byte writes
    • 's' SHOW val : show first and last 60 values in EEPROM for visual verify changes
    • 'I' is 128 INC : add 1 to all EEPROM values using 128 byte block update
    • 'p' is INC : SLOWEST EVIL :: perform 4096 individual writes of zero to each location
    • 'P' is 256 INC : add 1 to all EEPROM values using 256 byte block update
    • 'd' DWORD ZERO : zero all eeprom with 4 byte writes
    • 'w' WORD 0xFFFF : Put 0xFFFF to all eeprom 2 bytes at a time


    > All of EEPROM is READ to RAM array twice before start and compared - I saw errors once and this helped me find that is was (char) math compare when I wrote 255's
    > Error value only shown when not zero
    > The one second update is turned off just so those changes don't show as errors if the isr() changes values behind the requested update
    > All of EEPROM is READ to RAM array to start and compared for updated values when changed

    Most of my testing has been done on my original PROTO K66 - I've had it on some days where it updates all of EEPROM in under 1 hour 9 minutes. Plus some DOZENS (hundreds?) of using this sketch and prior ones to change ALL eeprom values with a key press. I have seen no failures or issues even from my earliest efforts 3 weeks back, and it is running now.
    Last edited by defragster; 10-03-2016 at 08:46 AM.

  19. #69
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,421
    Hi Defragster,

    Looks like you are having fun.

    As I mentioned, right now don't have full access to lots of my stuff, but still trying to play some. This morning, I took out one of my new Kickstarter 3.6 boards and thought I would give it a try.

    So I reinstalled Teensyduino to get a cleaner setup, then put in your two changed files. Looks like TYQT can see the serial number...

    I tried running the SerEEpromSysTick code and I tried to integrate in TyQt, and at times was not able to upload program and at times did not respond at all to serial data coming in. I had TyQt restore to not being integrated. Restarted Arduino 1.6.12 (64 bit) and then loaded blink, compiled and then plugged in T3.6 while holding program and it downloaded.

    I then tried downloading your sketch and tried loading Arduino Serial monitor, which does not come up and the Arduino compiler area starts showing:
    Error while setting serial port parameters: ...

    So then try to build blink, which automatic program fails, but pushing program button still works...

    Interesting, I thought I would check to see what the Teensy program says for versions and the like: So I clicked to turn off Auto mode, and then clicked the program button no Teensy (blink program). It compiles and then turns Automatic back on and does the program...

    Quick question: What version of TyQt should we try using? I simply downloaded the windows installer from the first posting in:
    https://forum.pjrc.com/threads/27825...highlight=tyqt
    Which is 0.7.6

    Now got to go check up on contractor...

  20. #70
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    Kurt - Hopefully that is just TYQT version 7.6 confusion? Current version comes from here: https://bintray.com/package/files/koromix/ty/ty

    Just went to TyQt-0.7.5-210 from two prior versions of 7.5 - all were working. The 7.5 version is the KS updated version I've been tracking - I'm not sure what is in the 7.6 as IIRC Koromix said to use 7.5.and I have not tried it as that file post linked above is just getting new 7.5's.

    Not sure if any of this helps or relates beyond using version 7.5 - I don't recognize those symptoms in my recent history - FAQ?:
    If you have TYQT open/integrated Teensy.exe should to be closed. If you want Teensy.exe you can click TYQT 'Serial' button to tell it to not monitor to allow programming - then Teensy.exe can see it - then enable Serial in TYQT. Of course Serial access is exclusive between SerMon and TYQT - TYQT can show Com# and have Serial disengaged I suppose and try with SerMon.

    Fun? - not sure about that anymore - seems like a chore now wanting to see if it is good enough to be done and move on. The PROTO K66 board has been updated each byte on the second for about 36 hours - about 31 iterations - and I just blasted a couple of full EEprom writes of 0 and 255 and Increment All and all is well . . .

    Will feel better when Paul gets a chance to review and provide feedback to make sure there isn't anything inherently unsafe or unacceptable. Only thing I know to worry over is what happens with 10,000 to 70,000 updates where it should survive and work if the real expected life would be 100,000? That could be done on a small 256-1K block on one - assuming if that area died the rest would be good. But it may be destructive - and not going to try that until the review comes in.

    Based on the line above - I should have my PROTO cycle over the 3rd or 4th Kilobyte only - it will cycle 4 times faster and if problems show the rest of flash should have life left.

    Funny - the end solution seems so clean and easy from where I started - like when I did the Interrupt Touch detection in a sketch after working hard to understand and get it right in what may have been 100 lines - it was about 20 lines when put in place in the core code - including .h edits.

  21. #71
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    noob question?
    They may be used but my efforts to prove that to myself failed so the edits I made - while in line with my other efforts - are not known to have executed these code paths.

    All the C code I tried resolve out to eeprom_write_byte() - even the ones from the eeprom/eeprom.CPP class which overloads the various operators.

    How do I effect a call to these teensy3/eeprom.c functions?:
    void eeprom_write_word(uint16_t *addr, uint16_t value)
    void eeprom_write_dword(uint32_t *addr, uint32_t value)
    void eeprom_write_block(const void *buf, void *addr, uint32_t len)

  22. #72
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,421
    I tried adding this line to a sketch: eeprom_write_word(0, 0x200);

    And it compiled fine. I did try to verify what code it generated... I would assume the same for the other two. Note: it appears like they are not int he keywords.txt file so they don't show up as keywords...

  23. #73
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    I'll try the obvious again. IIRC - I got compile errors . . . and left it at that and I task switched away . . .

    Who knows - maybe I had ESP8266 selected.

  24. #74
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,700
    KurtE - did you refer to the prototypes? The compiler is happy to eat your '0' address as a pointer that properly resolves out - but try it with a variable.

    Back to see the code I find this in avr\cores\teensy3\Eeprom.c::

    uint8_t eeprom_read_byte(const uint8_t *addr)
    uint16_t eeprom_read_word(const uint16_t *addr)
    uint32_t eeprom_read_dword(const uint32_t *addr)

    void eeprom_write_byte(uint8_t *addr, uint8_t value)
    void eeprom_write_word(uint16_t *addr, uint16_t value)
    void eeprom_write_dword(uint32_t *addr, uint32_t value)
    So what confused me ( and the compiler ) was how I pass a pointer usable by the function when it is just to be an offset?

    As I read this code - it will take the passed in memory address and use that as the offset?
    Code:
    void eeprom_write_word(uint16_t *addr, uint16_t value)
    {
    	uint32_t offset = (uint32_t)addr;
    	if (offset >= EEPROM_SIZE-1) return;
    // ...
    			*(uint16_t *)(&FlexRAM[offset]) = value;
    // ...
    It seems to me all of these should just be expecting the EEPROM address (i.e. offset) - not some pointer?::
    void eeprom_write_word(uint16_t addr, uint16_t value)

    If you agree I can change the code and test - but I didn't bother before and now I remember why.

  25. #75
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,421
    As far as I can tell, they are all expecting a 32 bit unsigned value to be passed in. That is the cast the pointer to a uint32_t value, where you only use the number of bytes that are appropriate. Not sure why they were defined this way...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •