Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 29 of 29

Thread: Help! Program works on T3.5 but fails on T4.x (DCC++)

  1. #26
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,739
    @KurtE
    Ran a test with analog read in the interrupt and worked down to 20us. This makes sense since analog read is taking about 17us.

    Did get response on github discussion:
    I guess that the problem is not in the analogRead but the integer lastCurrent. lastCurrent is several bytes wide so setting it is not an atomic operation. If you get an interrupt in the middle of setting lastCurrent then the value can be aything. As an int is 4 bytes on the Teensy and faster clock I guess that the chance that it is corrupted is much higher.
    So pretty much done until the next problem.

    Oh - forgot - someone tested to see if native ethernet was working with it and the short answer is yes it does.

  2. #27
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,707
    Cool! - you got it working

    Single 32 word is to be atomic - says Paul - is lastCurrent not a single 32 bit DWORD word ... from a single DWORD? Maybe it changes between READ and Assignment?

    If you ever have issues with atomic - see CORES::micros(). It reads local copy of two DWORDS from millis() realm - with that 'ANY interrupt' detected then re-read the 'enclosed' code {that has to be read only as write could/will repeat on ANY interrupt}. Total time for micros() is { with Paul ASM edit } about 36 cycles - reading two DWORDS and then doing the add to millisTick of the fractional diff between current CYCCNT and CYCCNT when the miilisTick was last updated - and Paul's added asm and Conditional to make sure at slow clocks don't wrap UP one ms if the millisTick is slow in coming - runs 2-4 clocks FASTER than original.

  3. #28
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    6,739
    Quote Originally Posted by defragster View Post
    Cool! - you got it working

    Single 32 word is to be atomic - says Paul - is lastCurrent not a single 32 bit DWORD word ... from a single DWORD? Maybe it changes between READ and Assignment?

    If you ever have issues with atomic - see CORES::micros(). It reads local copy of two DWORDS from millis() realm - with that 'ANY interrupt' detected then re-read the 'enclosed' code {that has to be read only as write could/will repeat on ANY interrupt}. Total time for micros() is { with Paul ASM edit } about 36 cycles - reading two DWORDS and then doing the add to millisTick of the fractional diff between current CYCCNT and CYCCNT when the miilisTick was last updated - and Paul's added asm and Conditional to make sure at slow clocks don't wrap UP one ms if the millisTick is slow in coming - runs 2-4 clocks FASTER than original.
    Not quite sure how that is being done but I did see in micros() looks like you have to wrap msec = systick_millis_count; with disabling the interrupt and then re-enabling it.

  4. #29
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,707
    Quote Originally Posted by mjs513 View Post
    Not quite sure how that is being done but I did see in micros() looks like you have to wrap msec = systick_millis_count; with disabling the interrupt and then re-enabling it.
    No interrupt disable! I should try looking at the Teensy3 code ( that does disable ) to replace when over 48 MHZ ( exclude T_LC with no CYCCNT and slow speed issue ? - but ould require CYCNT - and not having user using is and resetting it already for some reason )

    Every thing in the {do {} while ();} repeats if ANY interrupt is processed between __LDREXW and the __STREXW. Thus they should only be non-destructive reads - any INC++ or Write would repeat when it cycles.

    So when it exits the while() it is known there were no interrupts in getting a copy of those two variables.

    ...\hardware\teensy\avr\cores\teensy4\delay.c
    Code:
    uint32_t micros(void)
    {
    	uint32_t smc, scc;
    	do {
    		__LDREXW(&systick_safe_read);
    		smc = systick_millis_count;
    		scc = systick_cycle_count;
    	} while ( __STREXW(1, &systick_safe_read));
    	uint32_t cyccnt = ARM_DWT_CYCCNT;
    	asm volatile("" : : : "memory");
    	uint32_t ccdelta = cyccnt - scc;
    	uint32_t frac = ((uint64_t)ccdelta * scale_cpu_cycles_to_microseconds) >> 32;
    	if (frac > 1000) frac = 1000;
    	uint32_t usec = 1000*smc + frac;
    	return usec;
    }
    The 'systick_safe_read' is just a placeholder variable - doesn't have to be a related - the MCU just repeats the loop on ANY interrupt - not specific to any memory location.
    Looking at that asm again - it doesn't process anything - but that and the added conditional resulted in faster exec as noted ???

Posting Permissions

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