PDA

View Full Version : PWPS Servo Problem



louislouis
- 4th July 2022, 21:06
Hi Folks,
I actually discovered a problem with DT PWPS servo pulse generator.
If I use hardware USART (hserin) for receiving commands from Bluetooth module and the PWPS plugin is active (generating servo pulse) and I send a series of commands the PIC freezes. I think it is a collision with TMR1 because USART and PWPS use TMR1 interrupts.
Strangely with PIC16F688 all work with no issues, but with PIC16F1824 causes this strange behavior. These PICs are pin-compatible and interchangeable.
Then I try PIC12F1840 and same strange issues with freezing occurred. If I switch off PWPS the problem disappears.
On older PIC16F688 USART receiving and PWPS work perfectly as I said.
Has anyone encountered this problem?

richard
- 5th July 2022, 01:51
I think it is a collision with TMR1 because USART and PWPS use TMR1 interrupts.

why would the uart need a TMR1 interrupt ?

code ?

louislouis
- 5th July 2022, 10:37
Hi Richard,

I don't know, I'm just guessing.

Here the code for PIC 16F688 working just fine:


'* Notes : PIC16F688 *
'************************************************* ***************
#CONFIG
cfg = _INTRC_OSC_NOCLKOUT
cfg&= _WDT_ON
cfg&= _PWRTE_OFF
cfg&= _MCLRE_OFF
cfg&= _CP_OFF
cfg&= _CPD_OFF
cfg&= _BOD_ON
cfg&= _IESO_ON
cfg&= _FCMEN_ON
__CONFIG cfg
#ENDCONFIG

DEFINE OSC 4
OSCCON = %01100100

ANSEL = 0 ; set all digital
TRISA = %00000000 ; PORT A all output
TRISC = %00100001 ; PORT C.5 input RX, C.0 safety, rest output
CMCON0 = 7

; def_ports:
PWPSpin var portc.1 ; servo signal OUTPUT (must be defined before PWPS_Servo.INC)
safety var portc.0 ; safety leash magnetic switch

; def_vars:
n var byte
cmd var byte

; def HW USART:
DEFINE HSER_BAUD 9600 ; Set Baud rate to 9600bps
DEFINE HSER_CLROERR 1 ; Clear overflow error automatically
DEFINE HSER_TXSTA 24h ; Set receive register to TX en
define HSER_SPBRG 25
DEFINE HSER_SPBRGH 1
DEFINE HSER_RCSTA 90h

; def ext libr:
include "PWPS_Servo.INC" ; Software Servo PWM module

init: ; vars start values
position = 1
cmd = 245
n = 0

gosub StartPWPS ; start PWPS module

Main:

hSerin 20,lost, [wait("Q"),dec cmd] ; wait for Q and then for CMD

if cmd = 155 then ; increment servoimpulse
Position=Position+1
if Position > 1199 then Position = 1200 ; max servoimpulse lenght 2us
gosub SetPWPS
endif

if cmd = 145 then ; decrement servoimpulse
Position=Position-1
if Position < 1 then Position = 1 ; min servoimpulse lenght 1us
gosub SetPWPS
n=n+1 ; long press decrement
if n=255 then ; switch to minimum servoimpulse after cca. 3. sec.
position=1
endif
endif

if cmd = 245 then ; if transmitter is switched OFF servoimpulse to nimimum
Position=1
gosub SetPWPS
endif

if safety = 1 then ; if safety switch is OFF servoimpulse to nimimum
Position=1
gosub SetPWPS
endif

goto main

lost:
n=0 ; clear long press counter value to 0
if safety = 1 then ; if safety switch is OFF servoimpulse to nimimum
Position=1
gosub SetPWPS
endif
goto main


Here the code for PIC 16F1824 it causes collisions, the code is the same except config:


'* Notes : PIC16F1824 *
'************************************************* ***************

#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF
#ENDCONFIG

DEFINE OSC 4 ; Use a 4 MHZ internal clock
OSCCON = %01101000

ANSELA = 0
ANSELC = 0
TRISA = %000000
TRISC = %00100001 ; PORT C.5 input RX, C.0 safety, rest output
CM1CON0 = 0 ; Disable comparator 1
CM2CON0 = 0 ; Disable comparator 2
OPTION_REG.7=1 ; Disable weak pull ups
APFCON0.7=0
APFCON0.2=0


; def_ports:
PWPSpin var portc.1 ; servo signal OUTPUT (must be defined before PWPS_Servo.INC)
safety var portc.0 ; safety leash magnetic switch

; def_vars:
n var byte
cmd var byte

; def HW USART:
DEFINE HSER_BAUD 9600 ; Set Baud rate to 9600bps
DEFINE HSER_CLROERR 1 ; Clear overflow error automatically
DEFINE HSER_TXSTA 24h ; Set receive register to TX en
define HSER_SPBRG 25
DEFINE HSER_SPBRGH 1
DEFINE HSER_RCSTA 90h

; def ext libr:
include "PWPS_Servo.INC" ; Software Servo PWM module

init: ; vars start values
position = 1
cmd = 245
n = 0

gosub StartPWPS ; start PWPS module

Main:

hSerin 20,lost, [wait("Q"),dec cmd] ; wait for Q and then for CMD

if cmd = 155 then ; increment servoimpulse
Position=Position+1
if Position > 1199 then Position = 1200 ; max servoimpulse lenght 2us
gosub SetPWPS
endif

if cmd = 145 then ; decrement servoimpulse
Position=Position-1
if Position < 1 then Position = 1 ; min servoimpulse lenght 1us
gosub SetPWPS
n=n+1 ; long press decrement
if n=255 then ; switch to minimum servoimpulse after cca. 3. sec.
position=1
endif
endif

if cmd = 245 then ; if transmitter is switched OFF servoimpulse to nimimum
Position=1
gosub SetPWPS
endif

if safety = 1 then ; if safety switch is OFF servoimpulse to nimimum
Position=1
gosub SetPWPS
endif

goto main

lost:
n=0 ; clear long press counter value to 0
if safety = 1 then ; if safety switch is OFF servoimpulse to nimimum
Position=1
gosub SetPWPS
endif
goto main


Here is the PWPS include file:
9247

richard
- 5th July 2022, 12:17
What those two chips have in common is auto context save for interrupts.
i simulated the 1824 and the problem was not experienced, but who would trust a simulator



try this for 12f1840/16f1824 removing bogus context save/restore code




'************************************************* ***************'* Name : PWPS_Servo.INC Pulse Width Position Servo *
'* Author : Darrel Taylor *
'* Date : 5/1/2003 *
'* Version : 1.0 *
'* Notes : *
'* : *
'************************************************* ***************


DEFINE INTHAND INT_CODE ' Tell PBP Where the code starts on an interrupt


;wsave VAR BYTE $20 SYSTEM '$20 Save location for the W register if in bank0
;wsave1 VAR BYTE $A0 SYSTEM ' Save location for the W register if in bank1
;wsave2 VAR BYTE $120 SYSTEM ' Save location for the W register if in bank2
;wsave3 VAR BYTE $1A0 SYSTEM ' Save location for the W register if in bank3
;ssave VAR BYTE Bank0 SYSTEM ' Save location for the STATUS register
;psave VAR BYTE Bank0 SYSTEM ' Save location for the PCLATH register


W1 var word ' Temporary variable
y var byte ' Temporary variable
PulseTicks1ms var word ' # of Ticks for 1ms
TicksPeruSx100 var word ' # of Timer Ticks to = 1 us * 100
uS50Hz var word ' # of Ticks for 50 Hz with prescaler
PicOSC var byte Bank0 ' OSC value, Usable in PBP
OffTimePrescaler var byte ' Timer1 Prescale value during OFF period
Position var word ' 0 - 900 0 = 1.05ms 900 = 1.95ms
T1CONoff var byte Bank0
TMR1_ON_TICKS var word ' # of Tmr ticks for On Time
TMR1_OFF_TICKS var word ' # of Tmr ticks for Off Time
TMR1_ON_VAL var word Bank0 ' # to load TMR1 for On Time
TMR1_OFF_VAL var word Bank0 ' # to load TMR1 for Off Time


DataFlags var byte Bank0
Valid var DataFlags.0 ' 1 if Freq is valid - Set by CalcPWPS:
PWPSenabled var DataFlags.1 ' shows if PWPS is running or not
PWPSstate var DataFlags.2 ' Current state of PWPS output high or low


GIE var INTCON.7
PEIE var INTCON.6
TMR1IE var PIE1.0
TMR1ON var T1CON.0


goto GetOsc


' ------------------------------------------------------------------------
asm
INT_CODE
;if (CODE_SIZE <= 2)
; movwf wsave ; copy W to wsave register
; swapf STATUS,W ; swap status reg to be saved into W
; clrf STATUS ; change to bank 0 regardless of current bank
; movwf ssave ; save status reg to a bank 0 register
; movf PCLATH,w ; move PCLATH reg to be saved into W reg
; movwf psave ;6 ; save PCLATH reg to a bank 0 register
;endif

btfss PIR1, TMR1IF ; is TMR1IF set? Timer1 Interrupt Flag
GOTO NoTimerInt ; No. Bypass timer load
btfss _Valid ; Is Freq valid?
GOTO NoPWPS ; No. Halt PWPS
btfss _PWPSenabled ; is Software PWM enabled?
GOTO NoPWPS ; No. Halt PWPS
; Yes, then Set output and reload Timer1
btfss _PWPSstate ; Is Output High?
GOTO TurnON ;9/15 ; No.


TurnOFF
bcf _PWPSpin ; Set PWPSpin Low
bcf _PWPSstate ;
MOVF _T1CONoff,W ; Load OFF Period Prescaler and Turn off timer
MOVWF T1CON ;
MOVF _TMR1_OFF_VAL,W ; 1
ADDWF TMR1L,F ; 1 reload timer with Off Period value
BTFSC STATUS,C ; 1/2
INCF TMR1H,F ; 1
MOVF _TMR1_OFF_VAL+1,W ; 1
ADDWF TMR1H,F ; 1
BSF T1CON,TMR1ON ; 1 Turn it back on
GOTO TimerDone ;13/28


TurnON
bsf _PWPSpin ; Set PWPSpin High
bsf _PWPSstate ;
CLRF T1CON ; Clear Prescaler and Turn off timer
MOVF _TMR1_ON_VAL,W ; 1
ADDWF TMR1L,F ; 1 reload timer with On Period value
BTFSC STATUS,C ; 1/2
INCF TMR1H,F ; 1
MOVF _TMR1_ON_VAL+1,W ; 1
ADDWF TMR1H,F ; 1
bsf T1CON,TMR1ON ; 1 Turn it back on
GOTO TimerDone
NoPWPS
bcf T1CON,TMR1ON ; Turn off timer
bcf _PWPSpin ; Idle PWPSpin Low
TimerDone
bcf PIR1, TMR1IF ; 1/29 ; Clear Timer1 Interrupt Flag
NoTimerInt
;Movf psave,w ; Restore the PCLATH reg
;Movwf PCLATH
;swapf ssave,w ; Restore the STATUS reg
;movwf STATUS
;swapf wsave,f
;swapf wsave,w ; 6/35 ; Restore W reg

Retfie ; Exit the interrupt routine


endasm
' ------------------------------------------------------------------------


StartPWPS: ' Set Position before calling
low PWPSpin ' Set PWPSpin to Output and idle Low
GIE = 1 ' Global Interrupt Enable
PEIE = 1 ' Peripheral Interrupt Enable
TMR1H = 255 ' Load TMR1 with 65535, First tick will cause
TMR1L = 255 ' an interrupt that will load TMR1_???_VAL


SetPWPS: ' Set Position before calling
Position = Position min 1200 ' Make sure we don't go to far
gosub CalcPWPS
if Valid = 1 then
PWPSenabled = 1
lookdown OffTimePrescaler,[1,2,4,8],y
lookup y,[0,1,2,3],y
T1CONoff = y << 4
TMR1_ON_VAL = 65535 - TMR1_ON_TICKS + 7 ' Value to load in Timer1 for ON period
TMR1_OFF_VAL = 65535 - TMR1_OFF_TICKS + 7 ' Value to load in Timer1 for OFF period
TMR1IE = 1 ; Enable Timer1 Interrupts
T1CON = 1 ; Turn Timer1 on (no prescaler)
endif
return


StopPWPS
TMR1IE = 0
TMR1ON = 0
low PWPSpin ' Idle output Low
PWPSstate = 0
PWPSenabled = 0
return


CalcPWPS: ' Set Position before calling 0-900
Valid = 1
y = 99
LookDown PicOSC,[4, 8, 10, 12, 16, 20, 24, 25, 32, 33, 40],y
if y = 99 then OSCnotFound
;LookUp2 y,[ 1050, 2100, 2625, 3150, 4200, 5250, 6300, 6562, 8400, 8660, 10500],PulseTicks1ms
LookUp2 y,[ 900, 1800, 2250, 2700, 3600, 4500, 5400, 5625, 7200, 7425, 9000],PulseTicks1ms
lookup2 y,[ 100, 200, 250, 300, 400, 500, 600, 625, 800, 825, 1000],TicksPeruSx100
lookup y,[ 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4],OffTimePrescaler
Lookup2 y,[20000,40000,50000,60000,40000,50000,60000,62000,40 000,41000,50000],uS50Hz
W1 = TicksPeruSx100 * Position
W1 = Div32 100
TMR1_ON_TICKS = W1 + PulseTicks1ms
TMR1_OFF_TICKS = uS50Hz - (TMR1_ON_TICKS / OffTimePrescaler)
return


OSCnotFound:
Valid = 0
return




GetOsc: ' Retreive defined OSC value on Reset
asm
ifdef OSC
MOVE?CB OSC, _PicOSC
else
MOVE?CB 4, _PicOSC
endif
endasm

louislouis
- 5th July 2022, 13:14
Unfortunately, same behavior. After sending the command via Bluetooth (I send the command for example: hserout ["Q",dec 155,10,11] in a loop while the pushbutton is pressed). After a while, the servo output is incrementing and then suddenly freezes the PIC.

louislouis
- 5th July 2022, 22:21
I tested the PIC12F1840 and PIC16F1824 with software serial input. PIC frequency set to 8MHz as required PBP at 9600 baud.
It's working, but the response is kinda slow.


'* Notes : PIC16F1824 *
'************************************************* ***************

#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF
#ENDCONFIG

DEFINE OSC 8 ; Use a 8 MHZ internal clock
OSCCON = %01110000

ANSELA = 0
ANSELC = 0
TRISA = %000000
TRISC = %00100001 ; PORT C.5 input RX, C.0 safety, rest output
CM1CON0 = 0 ; Disable comparator 1
CM2CON0 = 0 ; Disable comparator 2
OPTION_REG.7=1 ; Disable weak pull ups
APFCON0.7=0
APFCON0.2=0


; def_ports:
PWPSpin var portc.1 ; servo signal OUTPUT (must be defined before PWPS_Servo.INC)
safety var portc.0 ; safety leash magnetic switch

; def_vars:
n var byte
cmd var byte

; def ext libr:
include "PWPS_Servo.INC" ; Software Servo PWM module
include "modedefs.bas" ; modedefs must be after PWPS_Servo.INC otherwise it doesn't work

init: ; vars start values
position = 1
cmd = 245
n = 0

gosub StartPWPS ; start PWPS module

Main:

Serin2 portc.5,84,20,lost, [wait("Q"),dec cmd] ; wait for Q and then for CMD

if cmd = 155 then ; increment servoimpulse
Position=Position+1
if Position > 1199 then Position = 1200 ; max servoimpulse lenght 2us
gosub SetPWPS
endif

if cmd = 145 then ; decrement servoimpulse
Position=Position-1
if Position < 1 then Position = 1 ; min servoimpulse lenght 1us
gosub SetPWPS
n=n+1 ; long press decrement
if n=255 then ; switch to minimum servoimpulse after cca. 3. sec.
position=1
endif
endif

if cmd = 245 then ; if transmitter is switched OFF servoimpulse to nimimum
Position=1
gosub SetPWPS
endif

if safety = 1 then ; if safety switch is OFF servoimpulse to nimimum
Position=1
gosub SetPWPS
endif

goto main

lost:
n=0 ; clear long press counter value to 0
if safety = 1 then ; if safety switch is OFF servoimpulse to nimimum
Position=1
gosub SetPWPS
endif
goto main


Then I tested even only the PWPS run alone on PIC16F1824 and via serial terminal from PC sent a serial command and the PIC freezes.

Then I tested what if I stop TMR1 (of course PWPS stopped working) but the HW usart works without problems.

Something is wrong with this PWPS include but I can't figure out what.

richard
- 6th July 2022, 01:52
how sure are you that your code is compiled with the modified inc as i suggested ?

if you examine the lst file generated and search for NoTimerInt
do you see

9248


pbp can be tricky if multiple versions of inc files exist, sometimes the "wrong" version can be used inadvertently

louislouis
- 6th July 2022, 08:51
100% sure, here is my LST file:
9249

louislouis
- 6th July 2022, 16:37
Even in proteus 8 simulator appears the same behavior. After sending a few commands the PWPS stops working and the PIC freezes.
I tested PIC12F1840, that's strange.

richard
- 7th July 2022, 08:46
Yes a hserin timeout that is too small causes some grief even the odd reset, i had to increase it to 300 for hand typed input for a successful
test.
my previous tests had the timeout commented out because i cannot type at that rate

louislouis
- 7th July 2022, 09:25
Not helped at all, I try timeouts from 200, 300 up to 600 still freezes.

I go hunting a few 16F688 PICs in SMD package and stay with these chips in this application.