PDA

View Full Version : 16F1827 interrupt hosed



Macgman2000
- 17th October 2011, 23:15
This is very strange. I have the interrupt working with a toggle on RB1 while main is generating in a loop a pulse on RB0.
During power up both ports are putting out a toggle, but about 5 to 10 seconds after power on the interrupt generated toggle stops. Main still is toggling away. I went through and made sure other peripheral interrupt sources are off...

what am I missing? Would someone please load this code and verify that the interrupt is stopping for some reason?







' This code is for 16F1827 MCU with built in oscillator (Max Osc 32Mhz)
' Code requires PicBasic Pro 2.60 along with MPASM assembler

ASM
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _PLLEN_OFF & _LVP_OFF & _LVP_OFF & _STVREN_OFF

ENDASM
DEFINE OSC 8

' Define ADCIN parameters
DEFINE ADC_BITS 8 ' Set number of bits in result
DEFINE ADC_CLOCK 4 ' Set clock source, look on data sheet for chart
DEFINE ADC_SAMPLEUS 500 ' Set sampling time in uS

DEFINE INTHAND myint ' Setup interrupt handler

;************************************************* ******************************
;************************************************* ******************************
; System hardware configuration
;************************************************* ******************************
;************************************************* ******************************
OSCCON = %01110000 ' 8MHz internal
ANSELA = %00000001 ' all digital. A/D disabled
ANSELB = %00000000
TRISB = %00000000 ' set port directions 0 = output, 1 = input
TRISA = %00000001
ADCON0 = %00000111 ' Set PORTA digital 1, analog 0
APFCON0.0 = 1 ' CCP1 PWM output on RB0
APFCON0.3 = 1 ' CCP2 PWM output on RA7
APFCON1 = 1
CCPR1L = 64 ' Set PWM Duty-Cycle to 50%
CCPR2L = 64
PR2 = 49 ' Set PWM frequency
CCP1CON = %00000000 ' Mode select = PWM off , to turn on %00001100
CCP2CON = %00000000 ' Mode select = PWM off, to turn on %00001100
T2CON = %00000110 ' %00000100 = TMR2 ON 1:1 pre-scale
' %00000101 = TMR2 ON 1:4 pre-scale
' %00000110 = TMR2 ON 1:16 pre-scale
' %00000111 = TMR2 ON 1:64 pre-scale


;************************************************* ******************************
; Program variables
;************************************************* ******************************
ADCVAL var byte



;************************************************* ******************************
; Program constants
;************************************************* ******************************



;************************************************* ******************************
; Power on initialization to known port states
;************************************************* ******************************

PowerOn_init:
PortA = 0 ' force low to avoid glitches
POrtB = 0
PIR1 = 0 ' clear TMR1 int flag
PIE1 = %00000001 ' TMR1 int enabled
INTCON = %11000000 ' global & peripheral ints enabled
T1CON = %00010001 ' TMR1 1:2 prescale, timer1 on

;************************************************* ******************************
;************************************************* ******************************
goto mainloop
asm
; Save W, STATUS and PCLATH registers, if not done previously
myint
; retfie auto-restores w, status, bsr, fsr and pclath
bcf T1CON,TMR1ON ; stop timer 1
bcf PIR1,TMR1IF ; clear over flow flag
movlw 0xEF ; load timer for 16,535 * 2 prescaler interrupt on 16 bit timer
movwf TMR1H ; load high byte
movlw 0xEF
movwf TMR1L ; load low byte
bsf T1CON,TMR1ON ; re-enable timer 1
movlw 0x02
xorwf PORTB,f ; toggle RB1
retfie ; Return from interrupt

retfie ; Return from interrupt
endasm


mainloop:
adcin 0, adcval

LATB.0 = 1
pauseus (4*adcval) + 1000
LATB.0 = 0
pause 15

goto mainloop

cncmachineguy
- 18th October 2011, 00:19
Try adding BSR=0 as the first asm instruction in your ISR. If this works, I will be happy to explain why. But if not the reason will confuse the issue.

Macgman2000
- 18th October 2011, 00:37
Very strange...I did what you suggested but it only prolonged the end result. I am seeing two things when the interrupt crashes....either it hoses the main loop and the interrupt oscillates at a high frequency of 235 Khz or it completely stops and main keeps going with its toggle. This is what I added to the ISR.



asm
; Save W, STATUS and PCLATH registers, if not done previously
myint
; retfie auto-restores w, status, bsr, fsr and pclath

bcf BSR,0
bcf T1CON,TMR1ON ; stop timer 1
bcf PIR1,TMR1IF ; clear over flow flag
movlw 0xEF ; load timer for 16,535 * 2 prescaler interrupt on 16 bit timer
movwf TMR1H ; load high byte
movlw 0xEF
movwf TMR1L ; load low byte
bsf T1CON,TMR1ON ; re-enable timer 1
movlw 0x02
xorwf PORTB,f ; toggle RB1
retfie ; Return from interrupt

endasm

cncmachineguy
- 18th October 2011, 05:37
Try bsr=0. There maybe more bank select bit then just 1.Like this:


Myint
Bsr=0
asm
Rest of isr


OR


myint
asm
clrf bsr
rest of isr

cncmachineguy
- 18th October 2011, 05:52
here is what I think is happening:
When the INT is called, the state of the BSR is unknown. If the main program is doing something that requires bsr to be other then 0, when you enter the ISR you can't manipulate the things in the ISR because the wrong bank is selected.

When you added the BCF BSR,0 - This almost fixed it but not quite. When it stays in the ISR that is because you can't clear the flag (acting on wrong reg, NOT PIR) so the INT just fires forever. My guess is when you think the main is running without INT, that may be not true, it may be that you just aren't toggling the output so you think the ISR has not fired.

The easiest way I know of to troubleshoot this is using MPLAB SIM inside of MPLAB. put a breakpoint at the first line of the ISR, then when it fires you can single step through while watching reg's like port b and even better BSR!

Macgman2000
- 18th October 2011, 13:29
Thanks for your help! I will try your suggestion. I did notice one thing before leaving the office last night, when I remove the ADC from main everything works well. When I rerun the test using ADC enabled it screws things up. Do I need to also do something with T1CON like select a bank of memory that it can write to that is common across banks? some how I think writing to values to the timer is somehow not being read out of the correct bank at some point after the interrupt is enabled upon exit....just my guess.

Nick

cncmachineguy
- 18th October 2011, 13:34
BSR will be restored when you exit the ISR. That chip auto saves and restores W,PC,Status, BSR, I think. So no need to worry about it from the Main point of view. I have not checked the banks you are using in the ISR, but I am thinking since it works sometimes they may be all in BANK 0. Could be the ADC is whats creating the NON bank 0 setting in the BSR.

Macgman2000
- 18th October 2011, 19:59
Bert,

Thanks for the help. I used your suggestion in conjunction with BANKSEL T1CON at the start of the ISR after the ASM tag. It all works now!!!

Nick

cncmachineguy
- 18th October 2011, 21:25
do you understand why? sounds like you do. BTW DT_INT takes care of BSR for you I think. I am being pushed towards using them and prolly will end up there. Just an FYI.

Macgman2000
- 19th October 2011, 18:18
I am seeing something strange.....It seems I can not read my ADC's or run anything in main when my interrupt is enabled. What my code is supposed to do is output a 1.5ms pulse every 16ms for "home" position on 4 servo's in the interrupt. At any time an ADC value on 5 ADC's is above a threshold I want to stop the interrupt and run the scaled up ADC values to run my servo's in real time. What am I missing?





ASM
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _PLLEN_OFF & _LVP_OFF & _LVP_OFF & _STVREN_OFF

ENDASM
DEFINE OSC 8

;Define ADCIN parameters

DEFINE ADC_BITS 8 ' Set number of bits in result
DEFINE ADC_CLOCK 4 ' Set clock source, look on data sheet for chart
DEFINE ADC_SAMPLEUS 500 ' Set sampling time in uS

DEFINE INTHAND myint ' Setup interrupt handler

;************************************************* ******************************
;************************************************* ******************************
; System hardware configuration
;************************************************* ******************************
;************************************************* ******************************
OSCCON = %01110000 ' bit.7 =32MHz internal
ANSELA = %00000001 ' all digital. A/D disabled
ANSELB = %00000000
TRISB = %00000000 ' set port directions 0 = output, 1 = input
TRISA = %00000001
ADCON0 = %00000111 ' Set PORTA digital 1, analog 0
ADCON1 = %01000000


;************************************************* ******************************
; Program variables
;************************************************* ******************************
ADCVAL var byte bank0
ADCVAL2 var byte bank0
ADCVAL3 var byte bank0
ADCVAL4 var byte bank0
ADCVAL5 var byte bank0


;************************************************* ******************************
; Program constants
;************************************************* ******************************
centM con 1500 ;motor stop
forM con 2000 ;motor forward
revM con 1000 ;motor reverse



;************************************************* ******************************
; Power on initialization to known port states
;************************************************* ******************************

PowerOn_init:
PortA = 0 ' force low to avoid glitches
POrtB = 0
PIR1 = 0 ' clear TMR1 int flag
PIE1 = %00000001 ' TMR1 int enabled
INTCON = %11000000 ' global & peripheral ints enabled
T1CON = %00010001 ' TMR1 1:2 prescale, timer1 on

;************************************************* ******************************
;************************************************* ******************************
goto mainloop
asm
; Save W, STATUS and PCLATH registers, if not done previously
myint
; retfie auto-restores w, status, bsr, fsr and pclath
BANKSEL T1CON
clrf BSR
bcf T1CON,TMR1ON ; stop timer 1
bcf PIR1,TMR1IF ; clear over flow flag
movlw 0xBF ; load timer for 16,535 * 2 prescaler interrupt on 16 bit timer
movwf TMR1H ; load high byte
movlw 0xFF
movwf TMR1L ; load low byte

call _home

bsf T1CON,TMR1ON ; re-enable timer 1

; movlw 0x02
; xorwf PORTB,f ; toggle RB1
retfie ; Return from interrupt

endasm
home:
if adcval < 4 and adcval2 < 4 and adcval3 <4 and adcval4 < 4 and adcval5 < 4 then
PORTB = %00001111
pauseus 1500
PORTB = %00000000
endif
return


mainloop:
call readADC
call spin
' call forward
' call back
' call left
' call right
pause 15
goto mainloop

readADC:
adcin 0, adcval
ADCIN 1, adcval2
adcin 2, adcval3
adcin 3, adcval4
adcin 4, adcval5
return


spin:
if adcval > 4 then
LATB = %00001111
pauseus 6*(adcval) + 900
LATB = %00000000
endif
return


forward:
if adcval2 > 4 then
LATB = %00001100
pauseus 6*(adcval) + 900
LATB = %00000000
LATB = %00000011
pauseus 6*(adcval) + 900
LATB = %00000000
endif
return

back:
if adcval3 > 4 then
LATB = %00000011
pauseus 6*(adcval) + 900
LATB = %00000000
LATB = %00001100
pauseus 6*(adcval) + 900
LATB = %00000000
endif
return

left:
if adcval4 > 4 then
LATB = %00000101
pauseus 6*(adcval) + 900
LATB = %00000000
LATB = %00001100
pauseus 6*(adcval) + 900
LATB = %00001010
endif
return

right:
if adcval5 > 4 then
LATB = %00001010
pauseus 6*(adcval) + 900
LATB = %00000000
LATB = %00000101
pauseus 6*(adcval) + 900
LATB = %00001010
endif
return

mackrackit
- 19th October 2011, 18:30
Try changing

call readADC
call spin

to

GOSUB readADC
GOSUB spin

From the manual:

CALL

CALL Label

Execute the assembly language subroutine named Label.
GOSUB is normally used to execute a PICBASIC PRO™ subroutine. The main difference between GOSUB and CALL is that with CALL, Label=s existence is not checked until assembly time. Using CALL, a Label in an assembly language section can be accessed that is otherwise inaccessible to PBP.
See the section on assembly language programming for more information on CALL.

CALL pass ' Execute assembly language subroutine named _pass

Macgman2000
- 19th October 2011, 19:35
Hello Dave,

I changed the calls to subs and still nothing runs in main while the interrupt is enabled. I can't even get a simple portb.0 set / reset to give me anything on the I/O.

Nick

Darrel Taylor
- 19th October 2011, 20:18
CALL or GOSUB doesn't make any difference.
But you cannot run Basic Language statements in an Assembly Language interrupt.
Re-use of PBP's system variables will corrupt the main programs flow.

If you want to use Basic statements in ASM interrupts, you need to either use ON INTERRUPT or DT_INTS.

Macgman2000
- 19th October 2011, 21:36
Darrel,

How would I structure my code using your interrupt include file? I want to accomplish the following:

1). update 4 servo's with a refresh rate of 16ms. Pulse width on the servos range between 1 ~ 2 ms based on reading 5 ADC channels.

Best Regards,
Nick

Dick Ivers
- 20th October 2011, 01:29
I found this in the new PBP3 Reference Manual on page 264

"Whenever a block of inline Assembly Language is entered, PBP sets the bank-select register to BANK0".

So, why does Nick have to manually select BANK0 using BANKSEL T1CON? It's true that all of the registers in his ISR are in BANK0. And yes, all his A to D registers are in BANK1, but why isn't PBP doing the switch to BANK0?

cncmachineguy
- 20th October 2011, 04:22
Good catch! Looks like I updated pbp but not my brain. Yet another good reason to upgrade :)

Darrel are you referring to the pauseus? If so are the rest non system variable things?

Darrel Taylor
- 20th October 2011, 04:27
... How would I structure my code using your interrupt include file? ...

I guess the structure would look a lot like the examples found here ... http://www.darreltaylor.com/DT_INTS-14/hello.html
Look at the Hello World, Blinky Light, Elapsed Timer and then how they are combined 1-3.

Darrel Taylor
- 20th October 2011, 04:48
Darrel are you referring to the pauseus? If so are the rest non system variable things?
if adcval < 4 and adcval2 < 4 and adcval3 <4 and adcval4 < 4 and adcval5 < 4 then

That is a compound if statement, meaning there is more than one condition to be tested.
That requires it to store intermediate results in T? temp variables, which are part of PBP's system vaiables.
The compares themselves will call a library function that uses R? system vars.

PAUSEUS will overwrite the R0 system variable.
PAUSE would use R0 and R1.

It's very difficult to know which statements will interfere with which system variables.
So it's best not to tempt fate.

cncmachineguy
- 20th October 2011, 10:40
Thanks Darrel