News:

Let's find out together what makes a PIC Tick!

Main Menu

PIC10FF322 TMR0 and ADC

Started by tnencon, Oct 19, 2023, 12:50 PM

Previous topic - Next topic

tnencon

Hello;
The code I wrote using the TMR0 interrupt with PIC10F322 works without any problems. Likewise, I can read ADC without any problems. But when I use TMR0 and ADC in the same code, it does not work. I couldn't find the reason. I would be glad if you help me in this regard.
Kind regards...

ADC Read;
Device 10F322
Declare Xtal = 16
Declare Optimiser_Level = 2
Config FOSC_INTOSC, WDTE_OFF, MCLRE_OFF, CP_OFF, BOREN_OFF, PWRTE_OFF,LVP_On ,LPBOR_OFF,WRT_OFF
ANSELA = 1
TRISA = 1
OSCCON = $70        '16MHz Osc
Declare Adin_Res = 8
Declare Adin_Tad = FRC
Main:

Dim Adc_Value As Byte = 0
Dim Channel As Byte = 0

Do

  Adc_Value = ADC_Read(0)
  SerOut PORTA.1,396,[Dec3 Adc_Value,"  ",10,13]
  DelayMS 1000
Loop
GoTo Main


Proc ADC_Read(Channel As Byte),Byte
    ADCONbits_CHS0 = Channel.0
    ADCONbits_CHS1 = Channel.1
    ADCONbits_CHS2 = Channel.2
    ADCONbits_ADON = 1
    DelayUS 100   
    ADCONbits_GO_DONE = 1
    While ADCONbits_GO_DONE = 1 :      Wend        ' Poll the GO_DONE flag for completion of conversion
    Result = ADRES
EndProc

TMR0 Code;
Device 10F322
Declare Xtal = 16
Config FOSC_INTOSC, WDTE_OFF, MCLRE_On, CP_OFF, BOREN_OFF, PWRTE_OFF,LVP_On ,LPBOR_OFF,WRT_OFF
OSCCON = $70
TRISA = 4
ANSELA = 0

INTCONBits_GIE = 1      'Global Interrupt Enable bit
INTCONBits_PEIE = 0    'Peripheral Interrupt Enable bit
INTCONBits_TMR0IE = 1  'Timer0 Overflow Interrupt Enable bit
INTCONBits_INTE = 0    'INT External Interrupt Enable bit
INTCONBits_IOCIE = 0    'Interrupt-on-Change Interrupt Enable bit
INTCONBits_TMR0IF = 0  'Timer0 Overflow Interrupt Flag bit
INTCONBits_INTF = 0    'INT External Interrupt Flag bit
INTCONBits_IOCIF = 0    'Interrupt-on-Change Interrupt Flag bit

OPTION_REG.7 = 0            'Weak pull-ups are enabled by individual PORT latch values
OPTION_REGBits_INTEDG = 0  'Interrupt on falling edge of INT pin
OPTION_REGBits_T0CS = 0    'Internal instruction cycle clock (FOSC/4)
OPTION_REGBits_T0SE = 0    'TMR0 Source Edge Select bit
OPTION_REGBits_PSA = 0      'Prescaler is assigned to the Timer0 module
OPTION_REGBits_PS2 = 1      ' \
OPTION_REGBits_PS1 = 1      '  : Prescaler Rate Select bits 1:256
OPTION_REGBits_PS0 = 1      ' / 
TMR0 = 0
On_Hardware_Interrupt GoTo ISR_Handler
Dim Tick As Byte = 0
Dim Delay_Time As Dword = 10
Dim Second As Byte = 0
Dim Minute As Byte = 0
Dim Hour As Byte = 0
Dim Update As Bit
Symbol Led_Output = PORTA.1
Symbol Start_Input = PORTA.2
Main:
If Update = 1 Then
    Toggle Led_Output
    Update = 0   
EndIf
GoTo Main

ISR_Handler:
Context Save
If INTCONbits_TMR0IF = 1 And Start_Input = 0 Then
    INTCONbits_TMR0IF = 0
    Inc Tick
    If Tick>=61 Then
      Update = 1
      Tick = 0
      Second = Second +1
      If Second >= 60 Then
          Second = 0
          Minute = Minute +1
          If Minute >= 60 Then
            Minute = 0
            Hour = Hour +1
            If Hour>=24 Then Hour = 0
          EndIf 
      EndIf
    EndIf
 
ElseIf Start_Input = 1 Then
    Clear Tick
    Clear Second
    Clear Minute
    Clear Hour
    TMR0 = 0
    Clear Led_Output   
EndIf
Context Restore

TMR0 and ADC Code
Device 10F322
Declare Xtal = 16
Config FOSC_INTOSC, WDTE_OFF, MCLRE_On, CP_OFF, BOREN_OFF, PWRTE_OFF,LVP_On ,LPBOR_OFF,WRT_OFF,BORV_HI
OSCCON = $70
TRISA = 5
ANSELA = 1

INTCONBits_GIE = 1      'Global Interrupt Enable bit
INTCONBits_PEIE = 0    'Peripheral Interrupt Enable bit
INTCONBits_TMR0IE = 1  'Timer0 Overflow Interrupt Enable bit
INTCONBits_INTE = 0    'INT External Interrupt Enable bit
INTCONBits_IOCIE = 0    'Interrupt-on-Change Interrupt Enable bit
INTCONBits_TMR0IF = 0  'Timer0 Overflow Interrupt Flag bit
INTCONBits_INTF = 0    'INT External Interrupt Flag bit
INTCONBits_IOCIF = 0    'Interrupt-on-Change Interrupt Flag bit

OPTION_REG.7 = 0            'Weak pull-ups are enabled by individual PORT latch values
OPTION_REGBits_INTEDG = 0  'Interrupt on falling edge of INT pin
OPTION_REGBits_T0CS = 0    'Internal instruction cycle clock (FOSC/4)
OPTION_REGBits_T0SE = 0    'TMR0 Source Edge Select bit
OPTION_REGBits_PSA = 0      'Prescaler is assigned to the Timer0 module
OPTION_REGBits_PS2 = 1      ' \
OPTION_REGBits_PS1 = 1      '  : Prescaler Rate Select bits 1:256
OPTION_REGBits_PS0 = 1      ' / 
PIE1 = 0
PIR1 = 0
TMR0 = 0
WPUA = $0C                  'RA3 and RA2 Pull-up enable
On_Hardware_Interrupt GoTo ISR_Handler
Main:
    Dim Tick As Byte = 0
    Dim Delay_Time As Dword = 10
    Dim Second As Byte = 0
    Dim Minute As Byte = 0
    Dim Hour As Byte = 0
    Dim Update As Bit
    Dim Adc_Value As Byte = 0
    Dim Channel As Byte = 0
    Symbol Led_Output = PORTA.1
    Symbol Start_Input = PORTA.2
   
    Do
        If Update = 1 Then
            Adc_Value = ADC_Read(0)           
            Update = 0             
        EndIf   

    Loop

GoTo Main

Proc ADC_Read(Channel As Byte),Byte
    ADCONbits_CHS0 = Channel.0
    ADCONbits_CHS1 = Channel.1
    ADCONbits_CHS2 = Channel.2
    ADCONbits_ADON = 1
    DelayUS 100   
    ADCONbits_GO_DONE = 1
    DelayUS 100   
    While ADCONbits_GO_DONE = 1        ' Poll the GO_DONE flag for completion of conversion
    Wend

    Result = ADRES
EndProc

ISR_Handler:
Context Save PIE1,PIR1
If INTCONbits_TMR0IF = 1 And Start_Input = 0 Then
'    INTCONbits_TMR0IF = 0
    Inc Tick
    If Tick>=61 Then   
      Update = 1
      Tick = 0
      Second = Second +1
      If Second >= 60 Then
          Second = 0
          Minute = Minute +1
          If Minute >= 60 Then
            Minute = 0
            Hour = Hour +1
            If Hour>=24 Then Hour = 0
          EndIf 
      EndIf
    EndIf
 
ElseIf Start_Input = 1 Then
    Clear Tick
    Clear Second
    Clear Minute
    Clear Hour
    TMR0 = 0
    Clear Led_Output   
EndIf
INTCON = $A0
Context Restore


Since I do not have the PIC10F322 physically, I am testing the code with Proteus.

trastikata

Why do you disable the peripheral interrupts?

tnencon

It is used to activate PIE A/D converter interrupt, NCO interrupt, CLC interrupt and TMR2 to PR2 Match Interrupt.

trastikata

I didn't take the time to look thorough through your code and assumed you are using ADC interrupts.

tumbleweed

A couple of comments...

You should wait to set GIE until everything else is setup, something like...
On_Hardware_Interrupt GoTo ISR_Handler
INTCONBits_GIE = 1      'Global Interrupt Enable bit  (MOVED)
Main:

Then, in the ISR you have:
Context Save PIE1,PIR1
If INTCONbits_TMR0IF = 1 And Start_Input = 0 Then
'    INTCONbits_TMR0IF = 0
    Inc Tick
You should change this logic.
If TMR0IF is set you must clear it before exiting the ISR regardless of what Start_Input is set to.
I know you have
INTCON = $A0
Context Restore
but you need to change that too... never set GIE manually like that inside the ISR. Just clear the IF bits.

Also
Context Save PIE1,PIR1
No need to save PIE1, PIR1



tnencon

Quote from: tumbleweed on Oct 19, 2023, 11:21 PMA couple of comments...

You should wait to set GIE until everything else is setup, something like...
On_Hardware_Interrupt GoTo ISR_Handler
INTCONBits_GIE = 1      'Global Interrupt Enable bit  (MOVED)
Main:

Then, in the ISR you have:
Context Save PIE1,PIR1
If INTCONbits_TMR0IF = 1 And Start_Input = 0 Then
'    INTCONbits_TMR0IF = 0
    Inc Tick
You should change this logic.
If TMR0IF is set you must clear it before exiting the ISR regardless of what Start_Input is set to.
I know you have
INTCON = $A0
Context Restore
but you need to change that too... never set GIE manually like that inside the ISR. Just clear the IF bits.

Also
Context Save PIE1,PIR1
No need to save PIE1, PIR1



Thanks for your comments, tumbleweed.
I made the necessary changes to the program, but the result did not change.ADC only reads once. When I call the ADC reading procedure within the TMR0 interrupt, it works fine. Why doesn't the ADC reading procedure work properly when I call it in the main program? I ask myself this question.

RGV250

Hi,
I am not sure of the problem but a couple of observations.
You do not need the Goto Main after the "Loop" statement as it will never get processed.
If I were doing this I would just have the Inc Tick inside the interrupt and then have a proceedure to do all the other code which would simplify your interrupt routine.
You use Inc Tick but then for Second, Minute & Hour use Second = Second + 1 etc. Inc is much neater.
Do you know the routine is actually working, you have clear Led_Oputput but I cannot see where you set it.

Bob

Stephen Moss

@tnencon are sure your TMR0 only code was functioning correctly?
I ask because with the internal pull-ups enabled and the switch connecting to Ground it looks like you want it to reset when the switch is pressed taking the input low.
If so then I think you will find you have that the values of Start_Input = in your ISR reversed, as the internal pull-up will be keeping Start_Input High most of the time and so Tick is constantly being cleared by the ISR, thus it never reaches or exceeds 61, Input is never set to 1 so the ADC procedure is never called.

Therefore in your interrupt I think you need to change...
If INTCONbits_TMR0IF = 1 And Start_Input = 0 Then to
If INTCONbits_TMR0IF = 1 And Start_Input = 1 Then and change
ElseIf Start_Input = 1 Then to
ElseIf Start_Input = 0 Then
Whether or not that will also resolve the Stack Overflow issue Proteus is report I don't know.

tnencon

Quote from: Stephen Moss on Oct 20, 2023, 11:21 AM@tnencon are sure your TMR0 only code was functioning correctly?
I ask because with the internal pull-ups enabled and the switch connecting to Ground it looks like you want it to reset when the switch is pressed taking the input low.
If so then I think you will find you have that the values of Start_Input = in your ISR reversed, as the internal pull-up will be keeping Start_Input High most of the time and so Tick is constantly being cleared by the ISR, thus it never reaches or exceeds 61, Input is never set to 1 so the ADC procedure is never called.

Therefore in your interrupt I think you need to change...
If INTCONbits_TMR0IF = 1 And Start_Input = 0 Then to
If INTCONbits_TMR0IF = 1 And Start_Input = 1 Then and change
ElseIf Start_Input = 1 Then to
ElseIf Start_Input = 0 Then
Whether or not that will also resolve the Stack Overflow issue Proteus is report I don't know.
You are right, I deleted the line "WPUA = $0C 'RA3 and RA2 Pull-up enable" while editing the code. It was actually in the code.
You can already see the pull-up definition in the code with TMR0 and ADC.
Thanks.

tumbleweed

QuoteWhether or not that will also resolve the Stack Overflow issue Proteus is report I don't know.
The stack overflow is due to re-enabling interrupts inside the ISR (INTCON = $A0) instead of letting the retfie do it.

If INTCONbits_TMR0IF = 1 then clear it no matter what the state of other variables are, otherwise you'll get tossed right back into the ISR when it exits.



trastikata

#10
Can you you use the LED to verify whether or not the program returns from the ISR?

tnencon

Quote from: trastikata on Oct 20, 2023, 05:21 PMCan you you use the LED to verify whether or not the program returns from the ISR?
Of course, I use the LED as an indicator in the experiments.

trastikata


Of course, I use the LED as an indicator in the experiments.
[/quote]

So the program exits the ISR?

tnencon

The program exits ISR. But the ADC reads only once. However, when I move the main program into TMR0, it makes ADC readings every second (I make ADC readings every second in the program). I monitor the ADC reading with the watch window on Proteus and the Last ADC Voltage value.

trastikata

Quote from: tnencon on Oct 20, 2023, 09:34 PMThe program exits ISR. But the ADC reads only once. However, when I move the main program into TMR0, it makes ADC readings every second (I make ADC readings every second in the program). I monitor the ADC reading with the watch window on Proteus and the Last ADC Voltage value.

Let me see if I understand the program

- the ADC reads only if Update=1
- Update is set, i.e. =1, when tick >=61
- tick is being incremented only if Start_Input = 0 at each TMR0 overflow, which is about 16.5 ms
- Start_Input is a button
- once taken an ADC sample, update is cleared

So you have to hold down the button for at least one second to take one ADC readng. Releasing the button basically stops the tick increment and thus update wont get set to re-allow another ADC sample. Is that what you intend in your code?

Pepe

It's another Proteus bug, for it to work you have to put PIR1 = 0 on the interrupt so that it doesn't enter it back into it

okmn

#16
if i did not understandt wrong code is work led as toggle when you pressed the button

i just  changed first "ADCONbits_GO_DONE" 1 to 0
ADCONbits_GO_DONE = 0 
While ADCONbits_GO_DONE = 1

tnencon

Quote from: Pepe on Oct 20, 2023, 11:47 PMIt's another Proteus bug, for it to work you have to put PIR1 = 0 on the interrupt so that it doesn't enter it back into it
Thank you very much Pepe. I think the problem is caused by Proteus. Actually, I need to clear PIR1 even though I do not use PERIPHERAL INTERRUPT in the code. I wonder if I would encounter this error if I had the PIC10F322.

tumbleweed

QuoteActually, I need to clear PIR1 even though I do not use PERIPHERAL INTERRUPT in the code. I wonder if I would encounter this error if I had the PIC10F322
I seriously doubt you'd see the same problem using the chip.

If you look at the datasheet Figure 6-1, as long as you have PEIE set to 0 (INTCON.6) then all interrupts in PIR1 are disabled.
There's no documented errata for the chip regarding this, so as pointed out it's likely just another Proteus bug.