Interrupts interfering with PRINT


Closed Thread
Results 1 to 8 of 8
  1. #1
    Join Date
    Sep 2006
    Location
    Reading, UK
    Posts
    15

    Default Interrupts interfering with PRINT

    Hello,

    I have a 16f876a running at 20MHz. It's connected to 2 H-bridges (of Bob Blick's design as can be seen at http://www.bobblick.com/techref/proj...e/hbridge.html) which I'm using to control two motors via PWM. Initially I was doing the pwm in software manually on each cycle round my program by varying the on/off time ratio at the end of each loop round the program. This worked, but because I was doing quite a few other things each loop I was getting a very low frequency of pwm - around 10-20hz I believe. (I don't have an oscillioscope so can't be sure of the exact frequency, but that's my best guestimate).

    The logical solution I figured was to do the pwm using an interrupt routine driven by timer0. This works - I'm getting an (audibly and visibly) much smoother control of the motor speed. Trouble is the LCD display to which I was outputting program data each loop is now showing partially or completely scrambled data. I assume that the PRINT commands I'm using are being rudely interrupted by my timer interrupt and that this is screwing up the timing of the data transmission to the LCD display.

    How can I avoid this? I've tried reducing the frequency of the pwm (by adjusting the values placed in PS2:PS0) but this doesn't solve the problem, not to mention that it defeats the point of the whole exercise. My ISR is fairly short (assembly code below), so I presume I'm not taking too long.

    Incidentally - if you're wondering why I don't just use hardware pwm, the problem is that each h-bridge requires an input for each direction of motor operation - that's 4 outputs from the PIC in total. As I recall (can't find the specs now), an 876a only has 2 or 3 hardware pwm channels.

    If it's the case that serivicing interrupts messes up the timing for picbasic commands doesn't that rather limit their utility? Or am I just doing something really wrong.

    Any help/ideas/pointers is really appreciated because I don't think I can progress any further without some assistance.

    Thanks,
    Luke

    Here's the asm code for the ISR. I am doing a RESUME at the end. pwmm1spd is a byte variable with the desired motor speed in it. intCount is a byte variable that just increments each time round the ISR. each time it hits zero is one cycle of pwm, so my pwm has a 'resolution' of 256 degress of on/offness. Hope that makes sense:



    movfw pwmm1spd
    subwf intCount, w
    btfsc STATUS, C
    goto PWMOFF
    PWMON:
    movlw 1
    subwf direction, w
    btfsc STATUS, Z
    goto FORWARD
    bcf M1B
    bsf M1F
    bcf M2F
    bsf M2B
    goto DONEPWM
    FORWARD:
    bcf M2B
    bsf M2F
    bcf M1F
    bsf M1B
    goto DONEPWM
    PWMOFF:
    ; Turn everything off
    bcf M1F ; Since this is the down part of the cycle
    bcf M1B ; Easier to turn everything off than test
    bcf M2F ; which motors to turn off...
    bcf M2B
    DONEPWM:
    decfsz intCount, 1 ; Decrement intCount
    goto intDoneStuff ; if NOT ZERO, then jump to intDoneStuff
    movlw 255 ; otherwise (if 0)... 255 into w
    movwf intCount ; reset counter
    intDoneStuff:
    bcf T0IF ; Clear the TMR0 overflow flag

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    <bgsound src="http://www.darreltaylor.com/files/cricket.wav" LOOP=5>Writes to the LCD are Synchronous. So they won't be affected by Interrupts, as long as the interrupts follow the rules.

    Typically, when they do interfere, it's because the "Context" hasn't been saved/restored properly.

    If the code shown above is the entire interrupt handler, then it's definitely missing the Restore.
    DT

  3. #3
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Default

    To pick up where Darrel Left off: Giving us more of your code will help keep us from playing twenty questions and guessing at the problem.

    Also look at the vB Code page to see how you can use the [code]...[/code] to make the code you post look like this:

    Code:
    X VAR BYTE
    Y VAR BYTE
    
    X = Y
    It will make it a lot more readable (especially for a lot of code).

    Steve B

  4. #4
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898


    Did you find this post helpful? Yes | No

    Default

    I assume that the PRINT commands I'm using are being rudely interrupted by my timer interrupt and that this is screwing up the timing of the data transmission to the LCD display.
    We are ready to help, but you're probably using PROTON compiler. SO you're on the wrong forum to have the full compiler understanding here.

    www.picbasic.org/forum
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  5. #5
    Join Date
    Sep 2006
    Location
    Reading, UK
    Posts
    15


    Did you find this post helpful? Yes | No

    Default

    Actually I am using Proton. I posted here automatically because I'm used to reading this forum. Would I be better off posting it elsewhere (at www.picbasic.org/forum)?

    Nontheless, here's a stripped down version of the full thing. (Which I compiled and tested to make sure it exhibits the same behaviour as the full version - it does!) Hopefully it's not too unintelligible. At the moment it's taking a value from a pot and placing it in pwmm1spd which the ISR uses to determine the duty cycle. When PORTB.7 is high it goes into a loop and spits some data out to the LCD.

    Thanks again. Any input is really appreciated.

    Code:
    	Device 16F876A
    	Config HS_OSC, WDT_OFF, PWRTE_OFF
    	Xtal = 20
    	ON_INTERRUPT ipwm
    
    	' Assign some Interrupt associated aliases 
    	SYMBOL T0IE = INTCON.5 		' TMR0 Overflow Interrupt Enable 
    	SYMBOL T0IF = INTCON.2 		' TMR0 Overflow Interrupt Flag 
    	SYMBOL GIE = INTCON.7		' Global Interrupt Enable 
    
    	SYMBOL PS0 = OPTION_REG.0	' Prescaler ratio bit-0 
    	SYMBOL PS1 = OPTION_REG.1	' Prescaler ratio bit-1 
    	SYMBOL PS2 = OPTION_REG.2	' Prescaler ratio bit-2 	
    	SYMBOL PSA = OPTION_REG.3	' Prescaler Assignment (1=assigned to WDT 0=assigned to oscillator) 	
    	SYMBOL T0CS = OPTION_REG.5	' Timer0 Clock Source Select (0=Internal clock 1=External PORTA.4) 
    	
    	Declare	ADIN_RES		10	' Set number of bits in result
    	Declare	ADIN_TAD		FRC	' Set clock source (3=rc)
    	Declare	ADIN_STIME		10 	' Set sampling time in uS (was 50)
    		
    	Declare LCD_TYPE		ALPHA
    	Declare LCD_DTPIN		PORTC.0
    	Declare LCD_ENPIN		PORTC.5
    	Declare LCD_RSPIN		PORTC.4
    	Declare LCD_INTERFACE	4
    	Declare LCD_LINES		2
    	
    	symbol GLED				portb.5
    	symbol PWMCYLEN			60
    	symbol M1F				portb.4
    	symbol M1B				portb.6
    	symbol M2F				portb.2
    	symbol M2B				portc.7
    		
    	dim i					as dword
    	dim j					as dword
    	dim	h					as dword
    	dim	k					as dword
    	dim asenscalib			as word
    	dim asensor				as dword
    	dim	potval   			as word
    	dim angle				as dword
    	dim oldangle   			as dword
    	dim	arate				as dword
    	dim speed   			as dword
    	dim oldspeed			as dword
    	dim	spdout				as byte
    	dim	torque				as dword
    	dim ptime				as word
    	dim	aCon				as word
    	dim	arCon  			as dword
    	
    	dim pwmm1spd			as byte
    	dim pwmm2spd			as byte
    	dim pwmcycle			as word
    	dim incr				as dword
    	dim cpause				as byte
    
    	' PWM interrupt handler variables	
    	dim intCount 		 as byte
    	dim direction		 as byte
    	
    	GOTO overInterrupt
    
    	EDATA word 500, word 701, word 696, word 10, word 10
    
    	' Interrupt routine starts here 
    ipwm: 
    	asm
    
    	movfw 	pwmm1spd
    	subwf		intCount, w
    	btfsc		STATUS, C
    	goto		PWMOFF
    PWMON:
    	movlw   1
    	subwf	direction, w
    	btfsc	STATUS, Z
    	goto	FORWARD
    	bcf		M1B
    	bsf		M1F
    	bcf		M2F
    	bsf		M2B
    	goto		DONEPWM
    FORWARD:
    	bcf		M2B
    	bsf		M2F
    	bcf		M1F
    	bsf		M1B
    	goto		DONEPWM
    PWMOFF:
    	; Turn everything off
    	bcf	   	M1F		  	 ; Since this is the down part of the cycle
    	bcf		M1B			 ; Easier to turn everything off than test
    	bcf		M2F			 ; which motors to turn off...
    	bcf		M2B
    DONEPWM:
    	decfsz  intCount, 1			 ; Decrement intCount
    	goto 	intDoneStuff		 ; if NOT ZERO, then jump to intDoneStuff
    	movlw	255					 ; otherwise (if 0)... 255 into w
    	movwf	intCount			 ; reset counter
    intDoneStuff:
    	bcf	 T0IF 	   				 ; Clear the TMR0 overflow flag
    
    	endasm 
    	CONTEXT RESTORE	' Restore the registers and exit the interrupt 
    
    overInterrupt:
    	
    	TRISB = %10000011
    	TRISC = $00
    	TRISA = $FF
    	ADCON1 = %10000001
    	
    	M1F = 0	 		  ' Turn all motors off
    	M1B = 0
    	M2F = 0
    	M2B = 0
    	portb.2 = 0
    	delayms 25		  ' Wait for display (is this necessary?)				
    
    	print $FE, 1, "     Hello"	' Clear display and show Hello
    	delayms 333
    	print $FE, 1  				' Clear display
    	
    	pwmm1spd = 40
    	pwmm2spd = 40
    	intCount = 255
    	
    	' Initiate the interrupt 
    	GIE = 0 			' Turn off global interrupts 
    	PSA = 1 			' Assign the prescaler to external oscillator 
    	PS0 = 0 			' Set the prescaler 
    	PS1 = 0 			' to increment TMR0 
    	PS2 = 0 			' every 256th instruction cycle 
    
    	T0CS = 0 			' Assign TMR0 clock to internal source 
    	TMR0 = 0 			' Clear TMR0 initially 
    	T0IE = 1 			' Enable TMR0 overflow interrupt 
    	GIE = 1 			' Enable global interrupts
    
    	asenscalib = eread 0
    	ADIN 0, aCon
    	ADIN 2, arCon
    	aCon = aCon / 12
    	arCon = arCon * 35
    	oldspeed = 0
    	oldangle = 0
    	speed = 0
    	pwmcycle = 0
    	PORTB.5 = 0
    
    	incr = 1
    	i = 0
    	cpause = 0
    	delayms 10
    	
    loop:
    	while PORTB.7 = 1					' Then we're in calibrate mode
    
    ''''''''''' test code
    		  ADIN 0, potval
    		  pwmm1spd = potval >> 2
    '''''''''''''''''''''''''''''''''''''''
    
    '		  M1F = 0	 		  ' Turn all motors off
    '		  M1B = 0
    '		  M2F = 0
    '		  M2B = 0
    		  speed = 0						' Reset values in case we've already been running...
    		  arate = 0
    		  oldangle = 0
    		  ADIN 1, asensor
    		  ADIN 0, aCon
    		  ADIN 2, arCon
    		  aCon = aCon / 12
    		  arCon = arCon * 35
    		  if arCon < 0 then
    		  	  print at 1, 1, "aK:", #aCon, " arK:-", #arCon, "(/10k)"
    		  else
    		  	  print at 1, 1, "aK:", #aCon, " arK:", #arCon, "(/10k)"
    		  endif
    		  print 2, 1, "clb : ", #asensor, " (", #asenscalib, ")"
    		  if PORTB.1 = 1 then
    		  	 asenscalib = asensor
    			 ewrite 0, [asenscalib]
    		  endif	  
    	wend
    	' END OF CALIBRATION
    
    	' BALANCING ALGORITHM
    
    	direction = 1
    	ADIN 0, potval
    	pwmm1spd = potval >> 2
    	
    	goto loop
    
    	end

  6. #6
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898


    Did you find this post helpful? Yes | No

    Default

    In theory it's suppose to work, but i know i miss something in this one and with PROTON's HardWare/software Interrupt's stuff. I stay away of this compiler anyways since 'round 1 year.

    So i guess, the best way will be to use their forum to have the real answer for that.
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  7. #7
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Default

    I'm not up to speed on PROTON, but did see that the PRINT statements you use are not the same. The last one is missing the "AT" following the PRINT. I imagine this could cause some unexpected results.

    Code:
    if arCon < 0 then
         print at 1, 1, "aK:", #aCon, " arK:-", #arCon, "(/10k)"
    else
         print at 1, 1, "aK:", #aCon, " arK:", #arCon, "(/10k)"
    endif
    print 2, 1, "clb : ", #asensor, " (", #asenscalib, ")"
    Steve

  8. #8
    Join Date
    Sep 2006
    Location
    Reading, UK
    Posts
    15


    Did you find this post helpful? Yes | No

    Default

    Hi,

    Well spotted! Unfortunately putting it in doesn't seem to resolve the problem.

Similar Threads

  1. Memory use - how much do you use?
    By keymuu in forum mel PIC BASIC Pro
    Replies: 16
    Last Post: - 10th June 2009, 22:39
  2. Clock using Instant Interrupts
    By PICpocket in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 16th February 2009, 21:43
  3. Microcode studio - PIC16F877A Interrupts
    By mcbeasleyjr in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 8th January 2009, 06:10
  4. DT's Instant Interrupts trouble
    By Tomexx in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 24th November 2008, 20:48
  5. help: TMR0 interrupts disabling PORTAchange interrupts???
    By xnihilo in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 19th August 2008, 15:10

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

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