Interrupt on Change PIC16F1825 - Page 1
Forum section: electronics / general

author: Fab6657
author_rank: Contributor
timestamp: April 15, 2022, 08:23:25 am
content: Hey Guys,I try to develop a code in MicroBasic so far so good, idea is to use IOC on one Pin to reproduce PWM signal on another pin.Code is running but I have strange situation that I not unterstand on the PIC 16F1825.If I enable in register INTCON the IOC, my code run one or two times, and if I not enable the IOC in INTCON the code run well always !Seems for me that IOC is working also if I deactivate IOCIE in INTCON, what I cannot believe.Any idea or experience what I make wrong ?Thank a lot,

author: Fab6657
author_rank: Contributor
timestamp: April 15, 2022, 09:08:01 am
content: Some infos from my side, in the Datasheet it is mentioned that edge detection still work even if IOCIE is deactivated.I guess that may be the raison why my signal on replicated pin work, if the flag IOCAF if even setted in case of edge detection.Why I think that, is because I use also a timer to have regular time command interrupts and then made possible the processof the interrupt routine. But if so, I still not unterstand why the IOC interrupt create some strange activities !Brainstorming ongoing

author: jpanhalt
author_rank: Super Contributor
timestamp: April 15, 2022, 10:32:56 am
content: I don't understand the problem you are seeing. For example, you don't "enable a register" in INTCON. There are just the IOCIE enable and IOCIF bits. You cannot write to IOCIF (see below). You enable IOC by setting INTCON,IOCIEThe simplest way around my/our confusion is to show the pertinent part of your code.For starters, interrupt flags work even when interrupts are not enabled.* That can be useful if you do polling.With IOC, if an edge is not specified, then the IOC flag for that pin is NOT SET on change.However, if an edge is selected, then IOCAF will show for that pin on change and INTCON,IOCIF will also show regardless of IOCEN or GIE.So, "it is mentioned that edge detection still work even if IOCIE is deactivated" is true. There are 4 registers associated with IOC on PORTA for the 16F1825:1) IOCAP (set to 0 if you do not want a flag/interrupt to happen)2) IOCAN (set to 0 if you do not want a flag/interrupt to happen)3) IOCAF ( flag will be set for any active edge whether or not interrupts are enabled)4) INTCON,IOCIF (readable not writable)4) INTCON,IOCIE (IOCIE is readable and writable, IOCIF can only be read)5) INTCON, GIE (must be set for any interrupt to work)The only way to clear INTCON,IOCIF is to clear IOCAF.*IOCxF and INTCON,IOCIF might be considered exceptions, as an edge must be selected for the flags to show.Edit: Fixed typo for INTCON,IOCIE

author: Fab6657
author_rank: Contributor
timestamp: April 15, 2022, 12:46:22 pm
content: Thank for feedback, yes so far this is how I set the code. To be sure, I will start from scratch, that was a code from other project.I will make a first test only with IOC handling (I used additionnaly two other timers for other purpose), and now, no more code inside the project, just the required to debug my IOC routineIt may be hard if multiple interrupt reason may happen. Keep you informed here.

author: jpanhalt
author_rank: Super Contributor
timestamp: April 15, 2022, 01:33:09 pm
content: Multiple enabled interrupts are common. The first thing you do in the iSR is figure out which interrupt(s) -- usually only one with that chip -- you need to handle. Then, before leaving the ISR, check for others that may have occurred while there and be sure all relevant flags (i.e., flags that are enabled to cause an interrupt) are clear. Microchip goes into detail about how to do that.The best way to get a better answer, particularly for cut and paste code is to post your code. I have never known seen interrupts not work as expected in running hardware. Simulation is a different story.

author: Ian.M
author_rank: Super Contributor
timestamp: April 15, 2022, 02:02:16 pm
content: Yes.Your ISR tends to become a collection of if(){} block, one to handle each possible interrupt source, of the form:Code:if(INTCONbits.TMR0IF && INTCONbits.TMR0IE){//Your Timer 0 interrupt handler hereINTCONbits.TMR0IF=0;}Put the one(s) that require lowest latency first as the time to execute all the failed if() tests and skips does add up and if multiple interrupt flags have become set, you also have to worry about the execution time of handlers higher up in the ISR.Provided each handler cleans up its own interrupt source properly (some you directly clear the interrupt flag, others require particular SFRs to be accessed in a specific way to clear it), at the end of the ISR you don't have to worry about any interrupts that may have been missed while the ISR was executing as if it exits with an interrupt still pending, the ISR will be reentered immediately. Depending on the ISR execution time and the interrupt rates of each interrupt source, extra interrupts will only occur rarely to extremely rarely, so it isn't generally worth the overhead on each ISR exit of adding code to detect them and loop back to the start of the ISR to handle them without exiting and reentering the ISR.The&& INTCONxbits.interruptEin the if() condition isn't strictly necessary, but handles the case when you need to disable the handler for a particular peripheral while still having other handlers active. Otherwise, an interrupt could trigger execution of another supposedly disabled peripheral's handler as well as its own, if the other peripheral's interrupt flag was either left set or has become set.

author: Fab6657
author_rank: Contributor
timestamp: April 15, 2022, 05:46:42 pm
content: Thank for your additional feedback,started from scratch with only this IOC interrupt handling, and the code work fine.See scope, blue is input on RA0 with IOC activated and purple is output on RC1.Now I need to go back and add necessary function inside code for my project purpose,and unterstand what I made wrongKeep you in the loop...Fabrice

author: DavidAlfa
author_rank: Super Contributor
timestamp: April 15, 2022, 06:14:09 pm
content: Sorry, I can't stand these posts asking for help without providing any code.At least provide something, doesn't need to be the prettiest code in the world, but you might be doing a very simple mistake, taking seconds to discover.You get everyone moving, looking at the datasheets, explaining everything... don't be lazy and do your part, too.

author: Fab6657
author_rank: Contributor
timestamp: April 16, 2022, 09:53:08 am
content: HiSorry, that was never my intention, I was more looking for experience sharing and good practices tipps !See below my actual test code. PWM generation is working and signal copy per IOC also.I still have an issue in state 10 where poti is turned too on the right, the program bug, and I need to turn back left to run normally !Very strange for me, no really unterstand the situation. In state 60, PWM fully work from 0% to near 100% (I only use 8bits from 10bits PWM resolution),and here no issues at all with Poti and the ADC conversion.This are only tests purpose, usually the poti do not need to be turn in state 10, even not use in the final project purpose.Code:' *****************************************************************************' * * * * * * * * Hardware Test CNC2Laser V01, 16F1825 * * * * * * * *' *****************************************************************************' * * * * * * * * Version 4.0 * * * * * * * *' * * * * * * * * Update 15 April 2022 * * * * * * * *' *****************************************************************************' Timer6 ECCP PWM generation' Internal clock speed 16Mhz''' *******************************************************************************************************************************************' Definition of the microcontroller PIC16F1825'' +-------------------+' | |' +5V --+ VDD VSS +-- 0V (GND)' | |' Alarm Buzzer + Led (Out) --+ RA5 RA0 +-- ICSP - Pin 1 PC (In-IOC)' | PIC16F1825 |' Input Probe Z (In-IOC) --+ RA4 RA1 +-- ICSP - Pin 17 PC (In-IOC)' | |' Push Button (In) --+ RA3 RA2 +-- E-Stop Pin 11 PC (In-INT) + Poti as test PWM' | |' Pin 1 CNC (Out) --+ RC5 RC0 +-- LedS Status (Out)' | |' Pin 17 CNC (Out) --+ RC4 RC1 +-- Probe Z - PC (Out)' | |' Relay Alim Laser 12V (Out) --+ RC3 RC2 +-- PWM Laser (Out)' | |' +-------------------+program CNC2Laser_V01' Declarations sectionsymbol Buzzer = LATA.5 ' Define PORTA.5 as output for Buzzer Alerting + Ledsymbol Probe = PORTA.4 ' Define PORTA.4 as INPUT Z Probe measurementssymbol PushButton = PORTA.3 ' Define PORTA.3 as INPUT Main Pushbutton command (MCLR pin)symbol EStop = PORTA.2 ' Define PORTA.2 as INPUT for Estop Alertingsymbol Pin17PC = LATA.1 ' Define PORTA.1 as INPUT for Pin 17 from PC - actually as output for tests purposesymbol Pin1PC = PORTA.0 ' Define PORTA.0 as INPUT for Pin 1 from PCsymbol LedS = LATC.0 ' Define PORTC.0 as output for Status Ledsymbol ProbeZ = LATC.1 ' Define PORTC.1 as output for Probe Z announcementsymbol PWMLaser = LATC.2 ' Define PORTC.2 as output PWM Lasersymbol RelayLaser = LATC.3 ' Define PORTC.3 as output for Laser power relaysymbol Pin17CNC = LATC.4 ' Define PORTC.4 as output for Pin 17 to CNCsymbol Pin1CNC = LATC.5 ' Define PORTC.5 as output for Pin 1 to CNC' Program variablesdim CCPR as word Absolute $291 ' CCPR1L:CCPR1H at 291h on 16F1825dim Oldstate2 as bit ' Variable for status PushButtondim mesure as word ' Variable for Potentiometer readingdim reference as word ' Variable for PWM calculationdim StateCNC2Laser as byte ' Variable defining the State Machine of CNC2Laser' End declaration program variables' ************************************* Declaration of procedures and functions ****************************************************************' Interrupt proceduresub procedure Interrupt' Section detection signal changeif (IOCAF.0 = 1) and (StateCNC2Laser = 60) then ' IOC was detected on RA0 and State Machine okIOCAF.0 = 0ProbeZ = Pin1PC ' Output ProbeZ = PWM signal (PWM generation inside this program only for test purpose)end ifend sub' Procedure for small waiting routine, not used at all inside Main Loopsub procedure Wait25()delay_ms(25) ' Just delay of 25msclrwdt ' Needet because of disabled Interrupt during some parts of programend sub' Procedure reading Buttonsub procedure ReadButtonWE()if Button(PORTA, 3, 1, 1) thenOldstate2 = 1 ' Change flag status to detect push on the buttonend ifif Oldstate2 and Button(PORTA, 3, 1, 0) thenOldstate2 = 0 ' Clear Oldstate of the buttonclrwdtif StateCNC2Laser = 10 then ' First press, ready to activate the laserStateCNC2Laser = 50elseStateCNC2Laser = 10 ' Second press, stop the laserend ifend ifend sub' Procedure read potentiometer, define amplitude value in procedure DoubleSenssub procedure Potentiometre()mesure = ADC_read(2) ' read value of the potentiometer on RA2clrwdt ' just in case ofreference = mesure / 4 ' Value can be from 0 to 1024 (10bits), we need from 0 to 256end sub' ******************************************************************************************************************************************************' ********************************** END of the PROCEDURES, START MAIN Program ************************************************************************' ******************************************************************************************************************************************************main:' Registry definition for 16F1825 (see Datasheet)OPTION_REG = %10001000 ' No Prescaler 1/1 TMR0 (page 176), WPUEN deactivateWDTCON = %00010111 ' Prescaler 1/65536 Watchdog 2 Sec nominal, enabled per software (page 100)TRISA = %00011101 ' PortA.0 and PortA.1 Pin PC (In) - for test here RA1 as Output, PortA.2 EStop(In), PortA.3 PushButton (In), PortA.4 Probe (In), PortA.5 Buzzer (Out) - (page 122)WPUA = %00000000 ' Pull Up inactif at startup for all Port (page 124)TRISC = %00000000 ' All Port.C as Output (page 133)INLVLA = %00000000 ' All A ports as TTL voltage levelINLVLC = %00000000 ' All C ports as TTL voltage levelANSELA = %00000100 ' Configure AN A pins as digital I/O, and RA2 as Analog for PWM test by Poti (page 123)ANSELC = %00000000 ' Configure AN C pins as digital I/O, (page 134)ADCON0 = %00001001 ' Activate ADC converter Canal 2 actif (page 150) for PWM test, poti inputADCON1 = %00000000 ' See page 151CM1CON0 = %00000000 ' All comparators are deactivatedCM2CON0 = %00000000 ' ...CM2CON1 = %00000000 ' ...OSCCON = %01111000 ' Define Clock at 16 Mhz (page 68)OSCTUNE = %00000000 ' Oscillator running at factory calibration (page 70)IOCAP = %00000001 ' Activate Interrupt on Change port RA on rising edge (page 137) Test Poti PWMIOCAN = %00000001 ' Activate Interrupt on Change port RA on falling edge (page 138) Test Poti PWM' PWM settings from CCP ModulePR6 = %11111111 ' Define PR2 to xFF, (page 208 datasheet) - Fosc = 16MhzCCP1CON = %00001100 ' Single output mode output, P1A & P1B active high (page 224)PSTR1CON = %00001000 ' Assign P1D to PWM signal for Laser PWM (page 228)CCP1AS = %00000000 ' Autoshutdown (page 226)PWM1CON = %10000000 ' Autorestart and 0 cycle between transitions (no needet in single PWM)PIE3 = %00000000 ' Not Enable Timer6 Interrupt for PR6 (page 90) program HANG if enableCCPTMRS = %11111110 ' CCP1 based on Timer6 (page 225)PIR3 = %00000010 ' Clear Timer6 IntFlag' Enable and start Timer6 for PWM (Page 207)CCPR1L = 0 ' Duty cycle = 0% on beginningPIR3.TMR6IF = 0 ' Clear Interrupt flag (page 94)T6CON = %00000111 ' Start Timer6 with Prescaler 1:64 (page 190 datasheet)' Initialise variables valuesStateCNC2Laser = 10 ' Initial value of State of CNC2LaserOldstate2 = 0 ' ...LedS = 0 ' ShutOff Led and BuzzerBuzzer = 0RelayLaser = 0PWMLaser = 0ProbeZ = 0Pin1CNC = 0Pin17CNC = 0Pin17PC = 0 ' This port as output for test purpose' Activate interruptINTCON = %11001000 ' Enable GIE - PEIE Interrupt, activate IOC (see page 87 datasheet 16F1825 PDF in E:\Documentations)' ********************************************************** M A I N L O O P ****************************************************************while trueReadButtonWE()Potentiometre()Select case StateCNC2Lasercase 10CCPR1L = 0RelayLaser = 0ProbeZ = not(probeZ) ' For debugging purposeBuzzer = 0clrwdtReadButtonWE()case 50CCPR1L = 0while reference >= 20 ' Avoid that PWM laser will start with high powerPotentiometre()StateCNC2Laser = 50LedS = not(LedS) ' Flash Led and BuzzerBuzzer = not(Buzzer) ' As long Potentiometer is not near 0Wait25wendStateCNC2Laser = 60 ' Ready to activate LaserBuzzer = 0ProbeZ = 0 ' For test purpose, normally use for other functioncase 60 'Ok to pulse laserBuzzer = 0RelayLaser = 1 ' Activate power laserPotentiometre()CCPR1L = lo(reference) ' Resolution 10bits PWMclrwdtend selectwend' *********************************************************** M A I N L O O P ************************************************************************end. ' End of the Program

author: Fab6657
author_rank: Contributor
timestamp: April 17, 2022, 03:19:09 am
content: Hey,some news from the tests, by deactivating IOC in state 10 and reactivate by going in 60, no issues with poti anymore !Code:Select case StateCNC2Lasercase 10INTCON = %11000000 ' Deactivate IOC interrupts, not needed hereCCPR1L = 0RelayLaser = 0ProbeZ = not(probeZ) ' For debugging purposeBuzzer = 0clrwdtcase 50CCPR1L = 0while reference >= 20 ' Avoid that PWM laser will start with high powerPotentiometre()StateCNC2Laser = 50LedS = not(LedS) ' Flash Led and BuzzerBuzzer = not(Buzzer) ' As long Potentiometer is not near 0Wait25wendStateCNC2Laser = 60 ' Ready to activate LaserINTCON = %11001000 ' Reactivate IOC InterruptsBuzzer = 0ProbeZ = 0 ' For test purpose, normally use for other functioncase 60 'Ok to pulse laserBuzzer = 0RelayLaser = 1 ' Activate power laserPotentiometre()CCPR1L = lo(reference) ' Resolution 10bits PWMclrwdtend selectWhy, I not figure out yet ! I continu to looking for ...

author: Fab6657
author_rank: Contributor
timestamp: April 17, 2022, 06:00:04 am
content: Hey, me again,so I try to figure out what could happen to bring the program in a behaviour situation.It is happen triggered by IOC (at least it is how I unterstand). So I modified the Interrupt routine as follow:Code:sub procedure Interrupt' Section detection signal changeif IOCAF.0 = 1 then ' IOC was detected on RA0 and State Machine okIOCAF.0 = 0if StateCNC2Laser = 60 thenProbeZ = Pin1PC ' Output ProbeZ = PWM signal (PWM generation inside this program only for test purpose)elseProbeZ = not(ProbeZ) ' For debugging purposeend ifend ifend subAnd now I can see when the Pin ProbeZ is toggle during Poti movement !In the higher position the pin start to toggle and I can see 5µsec before a small impulse on the pin what is monitored by IOC.Just after, the ProbeZ pin start to toggle. Does an IOC can be triggered by so small voltage difference of 0.08V?I capture the events in some picture. Does is that possible so, or I miss something?Thank

author: Fab6657
author_rank: Contributor
timestamp: April 17, 2022, 06:11:37 am
content: So, as far i setted all level to TTL for IOC detection, I tested on RA0 with Schmitt Trigger CMOS levels, and now; it is running as expected. No voltage pics anymore.This change solved my problem :Code:INLVLA = %00000001 ' All A ports as TTL voltage level, except RA0 as Schmitt TriggerThis show me to really consider lots of possibilities, hardware or software.Was happy to have an oscilloscope. Without, certainly poor chance to figure out.

author: jpanhalt
author_rank: Super Contributor
timestamp: April 17, 2022, 11:06:59 am
content: Hi Fab,Very glad you got that part working. You're not the first by far who forgot to check INLVLx. It is something one needs to check in that series.

author: Fab6657
author_rank: Contributor
timestamp: April 17, 2022, 03:06:33 pm
content: Quote from: jpanhalt on April 17, 2022, 11:06:59 amYou have right, but to be honnest, I not expected this kind of issue. Good leason learnedAnd I setted in my code the TTL level first in the INVLVLA .But I guess more issues and problems will happen in this project !