PDA

View Full Version : Software PWM lockup on a 16F877A



comwarrior
- 27th June 2010, 20:43
16F877A @ 20MHz
I've finally sorted out the serial lines so that i receive test messages upon start-up...

the program is quite a simple way of doing an interrupt based software PWM (IMHO)

However...
it goes through a sequence designed to check i have everything setup properly, it flashes an LED and sends a couple of messages up the comm port...
At the moment, i have my laptop set to talk down the comm lines for diagnostics purposes...

The program gets into the main loop and then locks up...
according to what it throws back up the comm port, it receives two bytes from my laptop (not sent by me) 210 and 59 and then locks up. The two bytes are the same every time i run it...

the fact that it transmits these two bytes back successfully indicates the comms RX INT handler is behaving... not sure where these bytes come from but thats an issue to be sorted later...

This implementation is only a 10 channel software PWM system to test my code before moving onto a monster 50 PWM channels...
It uses TMR0-INT for the time slicing... it should already be set to FOSC/4 acording to the manual. The only thing i'm concerned about is that tmr0 is used by the watchdog...

Below is the code, i have no idea why it's crashing nor where it is crashing. Hopefully someone can spot a stupid mistake...
Be aware, some of the code is commented out because it's written for the target PIC18...


Define OSC 20 ' Set clock speed

'MEMCON.7 = 0 ' Disable external memory bus
ADCON1.0 = 1
ADCON1.1 = 1
ADCON1.2 = 1
ADCON1.3 = 1
TRISA = %00000000
TRISB = %00000000
TRISC = %00000000
TRISD = %00000000
TRISE = %00000000

PORTA = 0
PORTB = 0
PORTC = 0
PORTD = 0
PORTE = 0

'Setup UART1
'BAUDCON.3 = 0 ' (BRG16) 8 bit baud rate gen
'BAUDCON.1 = 0 ' (WUE) Wake up disabled
'BAUDCON.0 = 0 ' (ABDEN) Auto Baud disabled
'SPBRG = 64 '129 ' 19.2Kbps @ 20MHz
'TXSTA.6 = 0 ' (TX9) 8 bit transmission
'TXSTA.4 = 0 ' (SYNC) Asynchronous mode
'TXSTA.2 = 1 ' (BRGH) Low Speed
'TXSTA.5 = 1 ' (TXEN) Transmit enable
RCSTA.6 = 0 ' (RX9) 8 bit receive
RCSTA.3 = 0 ' (ADDEN) Address detect disabled
RCSTA.4 = 1 ' (CREN) Continueous recieve enabled
RCSTA.7 = 1 ' (SPEN) Port Enable

'DEFINE HSER_RCSTA 208
DEFINE HSER_TXSTA 32
DEFINE HSER_BAUD 19200
HSEROUT ["Initialising",10,13]
RXcounter VAR BYTE
RXBUFFER VAR BYTE[12]

C1B1 VAR PORTA.0
C1B2 VAR PORTA.1
C1B3 VAR PORTA.2
C1B4 VAR PORTA.3
C1B5 VAR PORTA.4
C2B1 VAR PORTB.0
C2B2 VAR PORTB.1
C2B3 VAR PORTB.2
C2B4 VAR PORTB.3
C2B5 VAR PORTB.4
'C3B1 VAR PORTD.1
'C3B2 VAR PORTD.2
'C3B3 VAR PORTD.3
'C3B4 VAR PORTD.4
'C3B5 VAR PORTE.0
'C4B1 VAR PORTE.1
'C4B2 VAR PORTE.2
'C4B3 VAR PORTE.3
'C4B4 VAR PORTE.4
'C4B5 VAR PORTE.5
'C5B1 VAR PORTE.6
'C5B2 VAR PORTE.7
'C5B3 VAR PORTF.0
'C5B4 VAR PORTF.1
'C5B5 VAR PORTF.2
'C6B1 VAR PORTF.3
'C6B2 VAR PORTF.4
'C6B3 VAR PORTF.5
'C6B4 VAR PORTF.6
'C6B5 VAR PORTG.0
'C7B1 VAR PORTG.1
'C7B2 VAR PORTG.3
'C7B3 VAR PORTG.4
'C7B4 VAR PORTG.5
'C7B5 VAR PORTG.6
'C8B1 VAR PORTG.7
'C8B2 VAR PORTH.0
'C8B3 VAR PORTH.1
'C8B4 VAR PORTH.2
'C8B5 VAR PORTH.3
'C9B1 VAR PORTH.4
'C9B2 VAR PORTH.5
'C9B3 VAR PORTH.6
'C9B4 VAR PORTH.7
'C9B5 VAR PORTJ.0
'C10B1 VAR PORTJ.1
'C10B2 VAR PORTJ.2
'C10B3 VAR PORTJ.3
'C10B4 VAR PORTJ.4
'C10B5 VAR PORTJ.5

PWMINT var byte[8]

PWMARKER var byte
PWMARKER = 1

BITCOUNTER VAR BYTE
BITCOUNTER = 1
PERIODCOUNTER VAR BYTE
PERIODCOUNTER = 1
PROGCOUNTER VAR BYTE
PROGCOUNTER = 1

'DV VAR BYTE[30] ; Program Duration Var
BV1 VAR BYTE ; Zone1 Red
BV2 VAR BYTE ; Zone1 Green
BV3 VAR BYTE ; Zone1 Blue
BV4 VAR BYTE ; Zone1 Yellow
BV5 VAR BYTE ; Zone1 White
BV6 VAR BYTE ; Zone2 Red
BV7 VAR BYTE ; Zone2 Green
BV8 VAR BYTE ; Zone2 Blue
BV9 VAR BYTE ; Zone2 Yellow
BV10 VAR BYTE ; Zone2 White
'BV11 VAR BYTE[30]
'BV12 VAR BYTE[30]
'BV13 VAR BYTE[30]
'BV14 VAR BYTE[30]
'BV15 VAR BYTE[30]
'BV16 VAR BYTE[30]
'BV17 VAR BYTE[30]
'BV18 VAR BYTE[30]
'BV19 VAR BYTE[30]
'BV20 VAR BYTE[30]
'BV21 VAR BYTE[30]
'BV22 VAR BYTE[30]
'BV23 VAR BYTE[30]
'BV24 VAR BYTE[30]
'BV25 VAR BYTE[30]
'BV26 VAR BYTE[30]
'BV27 VAR BYTE[30]
'BV28 VAR BYTE[30]
'BV29 VAR BYTE[30]
'BV30 VAR BYTE[30]
'BV31 VAR BYTE[30]
'BV32 VAR BYTE[30]
'BV33 VAR BYTE[30]
'BV34 VAR BYTE[30]
'BV35 VAR BYTE[30]
'BV36 VAR BYTE[30]
'BV37 VAR BYTE[30]
'BV38 VAR BYTE[30]
'BV39 VAR BYTE[30]
'BV40 VAR BYTE[30]
'BV41 VAR BYTE[30]
'BV42 VAR BYTE[30]
'BV43 VAR BYTE[30]
'BV44 VAR BYTE[30]
'BV45 VAR BYTE[30]
'BV46 VAR BYTE[30]
'BV47 VAR BYTE[30]
'BV48 VAR BYTE[30]
'BV49 VAR BYTE[30]
'BV50 VAR BYTE[30]

Mode VAR BYTE
Mode = 0

BV1[0] = 0
BV2[0] = 0
BV3[0] = 0
BV4[0] = 0
BV5[0] = 0
BV6[0] = 0
BV7[0] = 0
BV8[0] = 0
BV9[0] = 0
BV10[0] = 0

Gosub initcheck

'DEFINE USE_LOWPRIORITY 0
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts
'INCLUDE "ReEnterPBP-18LP.bas" ; Include if using Low Pr. PBP INTS

;----[High Priority Interrupts]-----------------------------------------------
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, _SOFTPWM, PBP, yes
; INT_Handler SSP_INT, _I2C-handler PBP, yes
INT_Handler RX_INT, _RX1_INT, PBP, yes
; INT_Handler TMR1_INT, _KEYPAD_HANDLER PBP, yes
endm

INT_CREATE ; Creates the High Priority interrupt processor
ENDASM
@ INT_ENABLE TMR0_INT ; Enable Timer 0 Interrupts
; INT_ENABLE SSP_INT ; Enables MSSP interupts
@ INT_ENABLE RX_INT ; Enables UART Recieve interupts
; INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

'Set-up MSSP
'SSPSTAT.7 = 1 ' Slew enabled for 400KHz
'SSPSTAT.6 = 0 ' Disable SMBus inputs
'SSPCON1.3 =
'SSPCON1.2 =
'SSPCON1.1 =
'SSPCON1.0 =
'SSPCON1.5 - 1 ' Enabled MSSP

' Setup interupt timers
' TMR0 - PWM
TMR0 = 0
'TMR0L = 0 ' Reset TMR0 counter Low byte
'TMR0H = 0 ' Reset TMR0 counter High byte
'T0CON.6 = 1 ' TMR0 as 8bit
'T0CON.5 = 0 ' FOSC/4 clock source
'T0CON.4 = 1 ' High to low
'T0CON.3 = 1 ' Prescaler not asigned
'T0CON.2 = 0 ' NA 'Select 1:16 prescale
'T0CON.1 = 0 ' NA 'Select 1:16 prescale
'T0CON.0 = 0 ' NA 'Select 1:16 prescale
'T0CON.7 = 1 ' TMR0 on

' TMR1 - keypad
'T1CON.7 = 1
'T1CON.6 = 0
'T1CON.5 = 1
'T1CON.4 = 1
'T1CON.3 = 0
'T1CON.1 = 0
'T1CON.0 = 1
goto loop

loop:
TOGGLE PORTD.0
Pause 100
goto loop

SOFTPWM:
IF Mode > 0 then
goto SOFTPWMAUTO
ELSE
GOTO SOFTPWMMAN
ENDIF

@ INT_RETURN
RETURN

SOFTPWMAUTO:
if bitcounter < BV1[PROGCOUNTER] then
HIGH C1B1
ELSE
LOW C1B1
ENDIF

if bitcounter < BV2[PROGCOUNTER] then
HIGH C1B2
ELSE
LOW C1B2
ENDIF

if bitcounter < BV3[PROGCOUNTER] then
HIGH C1B3
ELSE
LOW C1B3
ENDIF

if bitcounter < BV4[PROGCOUNTER] then
HIGH C1B4
ELSE
LOW C1B4
ENDIF

if bitcounter < BV5[PROGCOUNTER] then
HIGH C1B5
ELSE
LOW C1B5
ENDIF

if bitcounter < BV6[PROGCOUNTER] then
HIGH C2B1
ELSE
LOW C2B1
ENDIF

if bitcounter < BV7[PROGCOUNTER] then
HIGH C2B2
ELSE
LOW C2B2
ENDIF

if bitcounter < BV8[PROGCOUNTER] then
HIGH C2B3
ELSE
LOW C2B3
ENDIF

if bitcounter < BV9[PROGCOUNTER] then
HIGH C2B4
ELSE
LOW C2B4
ENDIF

if bitcounter < BV10[PROGCOUNTER] then
HIGH C2B5
ELSE
LOW C2B5
ENDIF

IF BITCOUNTER = 255 then
BITCOUNTER = 1
PROGCOUNTER = PROGCOUNTER + 1
ELSE
BITCOUNTER = BITCOUNTER + 1
ENDIF
Return

SOFTPWMMAN:
if bitcounter < BV1 then
HIGH C1B1
ELSE
LOW C1B1
ENDIF

if bitcounter < BV2 then
HIGH C1B2
ELSE
LOW C1B2
ENDIF

if bitcounter < BV3 then
HIGH C1B3
ELSE
LOW C1B3
ENDIF

if bitcounter < BV4 then
HIGH C1B4
ELSE
LOW C1B4
ENDIF

if bitcounter < BV5 then
HIGH C1B5
ELSE
LOW C1B5
ENDIF

if bitcounter < BV6 then
HIGH C2B1
ELSE
LOW C2B1
ENDIF

if bitcounter < BV7 then
HIGH C2B2
ELSE
LOW C2B2
ENDIF

if bitcounter < BV8 then
HIGH C2B3
ELSE
LOW C2B3
ENDIF

if bitcounter < BV9 then
HIGH C2B4
ELSE
LOW C2B4
ENDIF

if bitcounter < BV10 then
HIGH C2B5
ELSE
LOW C2B5
ENDIF

IF BITCOUNTER = 255 then
BITCOUNTER = 1
ELSE
BITCOUNTER = BITCOUNTER + 1
ENDIF
RETURN

RX1_INT:
RXBUFFER(RXcounter) = RCREG
HSEROUT [DEC RXBUFFER(RXcounter),10,13] ' test
IF RXBUFFER(RXcounter) = 255 and RXcounter = 11 then
BV1 = RXBUFFER[1]
BV2 = RXBUFFER[2]
BV3 = RXBUFFER[3]
BV4 = RXBUFFER[4]
BV5 = RXBUFFER[5]
BV6 = RXBUFFER[6]
BV7 = RXBUFFER[7]
BV8 = RXBUFFER[8]
BV9 = RXBUFFER[9]
BV10 = RXBUFFER[10]
RXcounter = 0
ENDIF

IF RXBUFFER(RXcounter) = 255 and RXcounter <> 11 THEN
toggle PORTB.7
HSEROUT ["RX ERROR",10,13]
RXcounter = 0
ENDIF

IF RXcounter = 12 then
toggle PORTB.7
RXcounter = 0
ENDIF

RXcounter = RXcounter + 1
@ INT_RETURN

'KEYPAD_HANDLER:
'If KEYPAD = 0 then
'@ INT_RETURN
' ENDIF

'IF KEYPAD = 1 then ;RED +
' If zone = 1 then
' BV1 = BV1 + 1
' ENDIF
' IF zone = 2 THEN
' BV6 = BV6 + 1
' endif
'endif

@ INT_RETURN

initcheck:
HSEROUT ["Initialising2",10,13]
toggle PORTB.7
Pause 200
toggle PORTB.7
Pause 200
toggle PORTB.7
Pause 200
toggle PORTB.7
Pause 200
toggle PORTB.7
Pause 200
toggle PORTB.7
Pause 200
toggle PORTB.7
Pause 200
toggle PORTB.7
Pause 200
toggle PORTB.7
Pause 200
toggle PORTB.7
Pause 200
Low PORTB.7
HSEROUT ["Initialised",10,13]
return

Any help appreciated...

comwarrior
- 27th June 2010, 20:48
i've just spotted a var error in softpwman routine...
I'll correct it now and post back...

:edit
Nope, still does it

comwarrior
- 28th June 2010, 22:30
right, i changed the PWM to use TMR2 and it still locks up...
The only thing i can think of now is to start disabling some of the routines to isolate the problem...

Can no one shed any light on this?

masosi
- 29th June 2010, 00:43
just a quick glance -


SOFTPWM:
IF Mode > 0 then
goto SOFTPWMAUTO
ELSE
GOTO SOFTPWMMAN
ENDIF

@ INT_RETURN
RETURN

shouldn't that be gosub softpwm... because otherwise it will not come back and process the @ INT_RETURN?

just a guess

comwarrior
- 29th June 2010, 01:12
Call me a Muppet and stripe me pink!

I could have sworn they were gosubs! Honestly... i seen gosubs...
Well spotted!

I'll re-program in the morning...

comwarrior
- 29th June 2010, 19:52
ok... getting annoyed!
Changed the goto's to gosubs... same fault...
Disabled BOTH interupts so that all it has to do is flash an LED using pauses... same fault...
I've disabled the watchdog, power on timer, brownout reset and LVP and it still does it...

i'm seriously lost now... Help needed

comwarrior
- 29th June 2010, 21:52
Just for the hell of it... I tried another PIC same model and it does it on that too...

Any help is VERY appreciated

comwarrior
- 29th June 2010, 22:08
You are not going to believe this!

i tried a test program, disabled analog, turns all ports to output, sets all ports to low and then enters the same loop to toggle the LED... SIMPLE!
It failed and locked up...

so i asked myself, what is the diference between the 3mm red LED on PORTB.7 and the one on PORTD.0? so i switched them over... same result...

Just for the hell of it, i switched the resisters over and tried it... and it works!
I switched the resisters back and it locks up...

I took the suspect resister out and stuck it on my multimeter... it read less than 1ohm!
The resisters are supposed to be 68 ohms... this one is a faulty one...

So, the problem must have been caused by too much current through one of the IO lines...
I have lost 4 days trying to debug a problem caused by a 5 pence component that i would have never suspected if i was anywhere near sane!

So now i'm going to re-enable all my code and try it... god darn it!

masosi
- 29th June 2010, 22:16
Haha good to hear you found a problem!
I know that feeling too well, you're not alone!

comwarrior
- 30th June 2010, 00:54
it's absolutely ridiculous though!
I would have expected a supply of 5V to kill a 3.3V 3mm red led...
but no, the PIC just had to be clever...
Anyways, it's bed time...

ScaleRobotics
- 30th June 2010, 17:48
just a quick glance -


SOFTPWM:
IF Mode > 0 then
goto SOFTPWMAUTO
ELSE
GOTO SOFTPWMMAN
ENDIF

@ INT_RETURN
RETURNshouldn't that be gosub softpwm... because otherwise it will not come back and process the @ INT_RETURN?

just a guess

Except, we are not supposed to gosub outside of our interrupt handlers.
See: http://www.picbasic.co.uk/forum/showthread.php?t=12578&p=83788#post83788

Does it work for you, or is it acting funny?

HenrikOlsson
- 30th June 2010, 20:03
Well, that's true if you jump out of the ISR never to RETURN to it. You can definetely GOSUB "out of" the ISR as long as you don't "wander off" and doesn't RETURN to within the ISR to finally end up at the INT_RETURN.


myINT:
GOSUB mySUB1
GOSUB mySUB2
TOGGLE PortB.0
@ INT_RETURN
The above will work just fine as long as mySUB1 and mySUB2 RETURN to within the ISR.

Darrel Taylor
- 30th June 2010, 21:08
With 18F's or 16F1's, you can get away with GOSUBing to other routines from the interrupt handler.

But with 12F's and 16F's, you are limited by a very small Stack (8 levels).
Most PBP statements only use 1 or 2, but a couple of them can use up to 4 levels, which only leaves 4 levels for your program and it's GOSUB's.

When you get an interrupt, the hardware itself uses 1 level.
When the interrupt happens, it could be 2 or 3 gosubs deep already in your main program.
Then using Basic Language statements in the interrupt handler will want some more levels.

If you use another level by gosubing from the handler, then you are really pushing your luck.
It may work fine for some programs, but it could be catastrophic for others.

With 18F's and 16F1's, there are plenty of stack levels to go around. But not with the "little" guys.

comwarrior
- 11th July 2010, 13:38
So far, she does run... however, i'm having a right mare with the comms hardware setup and the comms handler...(shakes head)
Now that i have 6 18F4550's from crownhill i may revert the program back to using them...
The program does sweet FA, everything is driven from interrupts, their is only the 'automatic' and 'manual' modes that have gosubs and they are correctly returned so i don't think it's over/under runs that are the problem now...

I'll post more info later on, I'm going to take a break for a couple of hours and have a blast on CnC...