attachInterrupt runnig problem ! (ZCD by ESP8266)

Hi All

I try create Zero Cross Detection with ESP8266 in Arduino IDE.

some operator inside attachInterrupt not work !

(x=++) or (x=x+1) not work but (c=a-b) working.

Can anyone help to resolve my mistake ?

Thanks

Armen

void ICACHE_RAM_ATTR ZCDInterrupt(); // define in RAM

volatile unsigned long SZCC=0; // Sum of Zero Cross Count
volatile unsigned long ZCTCurrent=0; // Zero Cross Time Start
volatile unsigned long ZCTStart=0; // Zero Cross Time Stop
volatile unsigned long ZCTPeriod=0; // Zero Cross Time Period
volatile boolean ZCStatus=0;              // Boolean to store ZCD

const byte ZCDPin = 13;


void ICACHE_RAM_ATTR ZCDInterrupt () {  
  ZCTStart = ZCTCurrent;  
  ZCTCurrent = micros();  
  SZCC = SZCC + 1 ; // This line and SZC++ NOT WORK !!!   
  ZCTPeriod = ZCTCurrent - ZCTStart ;     
  ZCStatus=HIGH;
}

void setup() {
  Serial.begin(115200);
  pinMode(ZCDPin, INPUT); 
  attachInterrupt(digitalPinToInterrupt(ZCDPin), ZCDInterrupt, RISING); //INPUT_PULLUP INPUT
  Serial.println();
  ZCTCurrent = micros();
}

void loop() {
  
    Serial.printf("1 ZCStatus: %i\t",ZCStatus) ;
    
    Serial.printf("1 ZCTStart: %i\t",ZCTStart) ;
    
    Serial.printf("1 ZCTCurrent: %i\t",ZCTCurrent) ;

    Serial.printf("1 ZCTPeriod: %i\t",ZCTPeriod) ;
    
    Serial.printf("1 SZCC: %i <-EOL\t",SZCC) ;
    
    Serial.println();
    
    ZCStatus=0;
    
    Serial.printf("2 ZCStatus: %i\t",ZCStatus) ;
    
    Serial.printf("2 ZCTStart: %i\t",ZCTStart) ;
    
    Serial.printf("2 ZCTCurrent: %i\t",ZCTCurrent) ;

    Serial.printf("2 ZCTPeriod: %i\t",ZCTPeriod) ;
    
    Serial.printf("2 SZCC: %i <-EOL\t",SZCC) ;
  
    Serial.println();
  
}

Result SZCC duplicate and SZCC++ or SZCC=SZCC+1 sometimes not running !

1 ZCStatus: 0	1 ZCTStart: 0		1 ZCTCurrent: 60097		1 ZCTPeriod: 0		1 SZCC: 0 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 0		2 ZCTCurrent: 60097		2 ZCTPeriod: 0		2 SZCC: 0 <-EOL	
1 ZCStatus: 0	1 ZCTStart: 0		1 ZCTCurrent: 60097		1 ZCTPeriod: 7177	1 SZCC: 1 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 60097	2 ZCTCurrent: 67274		2 ZCTPeriod: 7177	2 SZCC: 1 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 67274	1 ZCTCurrent: 77302		1 ZCTPeriod: 10028	1 SZCC: 2 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 67274	2 ZCTCurrent: 87281		2 ZCTPeriod: 9979	2 SZCC: 3 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 77302	1 ZCTCurrent: 87281		1 ZCTPeriod: 10026	1 SZCC: 4 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 87281	2 ZCTCurrent: 97307		2 ZCTPeriod: 10026	2 SZCC: 5 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 97307	1 ZCTCurrent: 107287	1 ZCTPeriod: 9980	1 SZCC: 5 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 107287	2 ZCTCurrent: 117311	2 ZCTPeriod: 10024	2 SZCC: 6 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 107287	1 ZCTCurrent: 127291	1 ZCTPeriod: 9980	1 SZCC: 7 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 117311	2 ZCTCurrent: 127291	2 ZCTPeriod: 9980	2 SZCC: 8 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 127291	1 ZCTCurrent: 137315	1 ZCTPeriod: 10024	1 SZCC: 8 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 137315	2 ZCTCurrent: 147297	2 ZCTPeriod: 9982	2 SZCC: 9 <-EOL	
1 ZCStatus: 0	1 ZCTStart: 137315	1 ZCTCurrent: 157322	1 ZCTPeriod: 10025	1 SZCC: 10 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 147297	2 ZCTCurrent: 157322	2 ZCTPeriod: 9980	2 SZCC: 11 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 157322	1 ZCTCurrent: 167302	1 ZCTPeriod: 9980	1 SZCC: 12 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 167302	2 ZCTCurrent: 177326	2 ZCTPeriod: 10024	2 SZCC: 12 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 177326	1 ZCTCurrent: 187307	1 ZCTPeriod: 9981	1 SZCC: 13 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 177326	2 ZCTCurrent: 197330	2 ZCTPeriod: 10023	2 SZCC: 14 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 187307	1 ZCTCurrent: 197330	1 ZCTPeriod: 9981	1 SZCC: 15 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 197330	2 ZCTCurrent: 207311	2 ZCTPeriod: 9981	2 SZCC: 16 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 207311	1 ZCTCurrent: 217337	1 ZCTPeriod: 10026	1 SZCC: 16 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 217337	2 ZCTCurrent: 227315	2 ZCTPeriod: 9978	2 SZCC: 17 <-EOL	
1 ZCStatus: 0	1 ZCTStart: 217337	1 ZCTCurrent: 237337	1 ZCTPeriod: 10022	1 SZCC: 18 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 227315	2 ZCTCurrent: 237337	2 ZCTPeriod: 9981	2 SZCC: 19 <-EOL	
1 ZCStatus: 1	1 ZCTStart: 237337	1 ZCTCurrent: 247318	1 ZCTPeriod: 9981	1 SZCC: 20 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 247318	2 ZCTCurrent: 257345	2 ZCTPeriod: 10027	2 SZCC: 20 <-EOL	
1 ZCStatus: 0	1 ZCTStart: 257345	1 ZCTCurrent: 267324	1 ZCTPeriod: 9979	1 SZCC: 21 <-EOL	
2 ZCStatus: 0	2 ZCTStart: 257345	2 ZCTCurrent: 277349	2 ZCTPeriod: 10025	2 SZCC: 22 <-EOL

You are printing multi-byte variables that are CHANGED by the interrupt handler. What happens when the interrupt occurs after you have read SOME of those bytes, but not ALL of them?

In loop(), you MUST disable interrupts, read the variable, re-enable interrupts, THEN print the variable.

Regards,
Ray L.

@Ray: Would the volatile keyword on the definition of ZCDPin solve his problem?

econjack:
@Ray: Would the volatile keyword on the definition of ZCDPin solve his problem?

Absolutely not! volatile simply ensures the code ALWAYS reads the value of the variable from memory, rather than using a (possible stale) cached value. It does absolutely nothing to protect against interrupts occurring during foreground reads or writes of multi-byte variables. That is done only by putting calls to noInterrupts()/interrupts() around such reads or writes.

Regards,
Ray L.

@Ray: I misread it, too. That pin's a const and not part of the ISR anyway. Sorry 'bout that.

econjack:
@Ray: I misread it, too. That pin’s a const and not part of the ISR anyway. Sorry 'bout that.

Sorry, yes ZCDPin is a const, so does not need to be protected. At run-time, the variable ZCDPin does not even exist any more.

But he reads and write ZCCP in the ISR, and reads it in loop, with NO protection.

Regards,
Ray L.

RayLivingston:
Sorry, yes ZCDPin is a const, so does not need to be protected. At run-time, the variable ZCDPin does not even exist any more.

But he reads and write ZCCP in the ISR, and reads it in loop, with NO protection.

Regards,
Ray L.

So what should I do when it's "NO protection" ?

Can you explain or edit code for test.

Thanks
Armen

Rmen:
So what should I do when it's "NO protection" ?

Can you explain or edit code for test.

Thanks
Armen

It's at the end of reply #3.

aarg:
It's at the end of reply #3.

Aha Thank

Esp8266 is a 32bit processor...

Look up “atomic operations ESP8266” to see a general discussion of this topic.
What, incidentally, do you expect this construct which is mentioned in the OP to do:
(x=++) or did you simply mean (x++) ?

Looks atomic to me…

40210af7:       ff9f21          l32r    a2, 40210974 ;literal pool: address of SZCC
40210afa:       ffd431          l32r    a3, 40210a4c <setup+0x64> ; address of format string.
40210afd:       0020c0          memw
40210b00:       0248            l32i.n  a4, a2, 0 ; 32bit load of SZCC value.
40210b02:       0c2d            mov.n   a2, a12  ; "Serial" ?
40210b04:       00ae45          call0   402115ec <Print::printf(char const*, ...

The ISR code looks OK too.

40210980 <ZCDInterrupt()>:
    :
402109a1:       fff421          l32r    a2, 40210974 <timer1_disable+0x1c>  ;; address of SZCC
402109a4:       0020c0          memw
402109a7:       0238            l32i.n  a3, a2, 0  ;; 32bit load
402109a9:       331b            addi.n  a3, a3, 1   ;; increment
402109ab:       0020c0          memw
402109ae:       0239            s32i.n  a3, a2, 0   ;; store.

(man, those “memw” instructions (something to do with memory ordering) just get sprinkled ALL OVER THE PLACE.)

Indeed. It does appear, from your analysis, that these are atomic 32 bit operations.

I've just looked more carefully at the OP's problem. It is not the typical case of a non-atomic operation where say an operation on a 32bit value is handled is handled as four separate 8 bit operations (like in the AVR world), and the read operation sees some intermediate state. In this case, it is simply that the loop() is running without any interlock, so can at times run twice, or more, between calls of the ISR. This gives rise to one of the problems reported by the OP that he is sometimes seeing duplicate values of DZCC. I guess if the frequency of the interrupts was higher, he'd then be complaining of missing instead of duplicate values.

Incidentally, I don't want to get too deep in the ESP8266 (Xtensa) instruction set, but I found this "crib sheet", which also mentions the memw synchronisation instruction: The ESP8266

Thanks for last 2 post
it's more professional code and I can't understand :o