Log in

View Full Version : Erratic LED blinking



Ioannis
- 30th May 2025, 00:45
On the uploaded YT video one can see that the LED is not blinking stable as it should.

Can anyone spot what is wrong with the code please?

That LED is driven from the in2 output port and while the halfbridge subroutine is called.

There is an ISR that updates some variables including the var named freq. This one defines the delay that Pause command uses.

Thanks,
Ioannis

https://youtu.be/Ja_IDIrpChM



'************************************************* ***************
'* Name : 47K42_Coil.BAS *
'* Author : Ioannis Kyriakidis *
'* Notice : Copyright (c) 2025 Signal Electronics *
'* : All Rights Reserved *
'* Date : 13/04/2025 *
'* Version : 1.0 *
'* Notes : 18F47K42 *
'* : *
'************************************************* ***************

#CONFIG
CONFIG FEXTOSC = OFF ;Oscillator not enabled
CONFIG RSTOSC = HFINTOSC_64MHZ ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
CONFIG CLKOUTEN = OFF ;CLKOUT function is disabled
CONFIG PR1WAY = OFF ;PRLOCK bit can be set and cleared repeatedly
CONFIG CSWEN = ON ;Writing to NOSC and NDIV is allowed
CONFIG FCMEN = ON ;Fail-Safe Clock Monitor enabled
CONFIG MCLRE = INTMCLR ;If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR
CONFIG PWRTS = PWRT_64 ;PWRT set at 64ms
CONFIG MVECEN = OFF ;Interrupt contoller does not use vector table to prioritze interrupts
CONFIG IVT1WAY = OFF ;IVTLOCK bit can be cleared and set repeatedly
CONFIG LPBOREN = OFF ;ULPBOR disabled
CONFIG BOREN = ON ;Brown-out Reset enabled according to SBOREN
CONFIG BORV = VBOR_245 ;Brown-out Reset Voltage (VBOR) set to 2.45V
CONFIG ZCD = OFF ;ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
CONFIG PPS1WAY = OFF ;PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence)
CONFIG STVREN = ON ;Stack full/underflow will cause Reset
CONFIG DEBUG = OFF ;Background debugger disabled
CONFIG XINST = OFF ;Extended Instruction Set and Indexed Addressing Mode disabled
CONFIG WDTCPS = WDTCPS_31 ;Divider ratio 1:65536; software control of WDTPS
CONFIG WDTE = SWDTEN ;WDT enabled/disabled by SWDTEN bit
CONFIG WDTCWS = WDTCWS_7 ;window always open (100%); software control; keyed access not required
CONFIG WDTCCS = LFINTOSC ;WDT reference clock is the 31.0 kHz LFINTOSC
CONFIG BBSIZE = BBSIZE_512 ;Boot Block size is 512 words
CONFIG BBEN = OFF ;Boot block disabled
CONFIG SAFEN = OFF ;SAF disabled
CONFIG WRTAPP = OFF ;Application Block not write protected
CONFIG WRTB = OFF ;Configuration registers (300000-30000Bh) not write-protected
CONFIG WRTC = OFF ;Boot Block (000000-0007FFh) not write-protected
CONFIG WRTD = OFF ;Data EEPROM not write-protected
CONFIG WRTSAF = OFF ;SAF not Write Protected
CONFIG LVP = OFF ;HV on MCLR/VPP must be used for programming
CONFIG CP = OFF ;PFM and Data EEPROM code protection disabled
#ENDCONFIG

DEFINE OSC 64

Include "c:\users\pikst\desktop\coil\DT_INTS-18xv.bas"
Include "c:\users\pikst\desktop\coil\ReEnterPBP-18xv.bas"
'Include "c:\users\pikst\desktop\coil\ReEnterPBP-18xvLP.bas"

;LCD Setup ************************************************** *******************

' Set LCD Data port
DEFINE LCD_DREG PORTD
' Set starting Data bit (0 or 4) if 4-bit bus
DEFINE LCD_DBIT 4
' Set LCD Register Select port
DEFINE LCD_RSREG PORTD
' Set LCD Register Select bit
DEFINE LCD_RSBIT 0
' Set LCD Enable port
DEFINE LCD_EREG PORTD
' Set LCD Enable bit
DEFINE LCD_EBIT 1
' Set LCD bus size (4 or 8 bits)
DEFINE LCD_BITS 4
' Set number of lines on LCD
DEFINE LCD_LINES 2
' Set command delay time in us
'DEFINE LCD_COMMANDUS 1500
' Set data delay time in us
'DEFINE LCD_DATAUS 250

' Congigure I/O Digital/Analog ********************************
ANSELA = %00000011 ' RA0, RA1 analog, other PORTA digital
ANSELB = %00000000 ' PORTB digital
ANSELC = %00000000 ' PORTC digital
ANSELD = %00001100 ' PORTD digital, RD2, RD3 Analog input for IS sense
ANSELE = %00000000 ' PORTE digital

LATA = %00000000
LATB = %00001010
LATC = %00000000
LATD = %00000000
LATE = %00000000

TRISA = %00000011
TRISB = %00000000
TRISC = %00000000
TRISD = %00001100
TRISE = %00000011

WPUE = %00000011

;************************************************* ********************
; ADC Settings
;************************************************* ********************
Define ADC_BITS 12 ' Set number of bits in result
Define ADC_SAMPLEUS 50 ' Set sampling time in uS

ADCON0 = %00010100 ' ADC clock = internal RC, right-justify ADC results in ADRES
'ADCON1=%10110000
'ADCON2=%00000000

'************************************************* ************
' Timer0 Setup
'************************************************* ************
T0CON0=%00010000 'Timer 0 set as 16bit timer
T0CON1=%01110000 'Timer 0 clock source Fosc=64MHz, Async

Timer0 var T0CON0.7'Timer Enable bit

TMR0H=$C1 'Load Timer 0 with start value $C187
TMR0L=$87 'to count up 16000 steps until rollover

'TImer0 Setup end ********************************************


'************************************************* ************
' PWM Setup
'************************************************* ************

TRISC.4=1 'Disable PWM port for setup

T2PR=255 'Period Register

'CCPTMRS0 = %01010101
CCPR1L=0
CCPR1H=0
CCP1CON = %10001100

PIR4.2=0 'Timer 2 Interrupt flag reset TMR2IF=0

T2CLK=%00000001 'Clock source for Timer 2 = Fosc/4
T2CON=%01100000 ' ON/OFF, prescaler, postscaler

T2CON.7=1 'Enable Timer 2

'PWM Setup end ***********************************************


'************************************************* ************
' Alias and Variables
'************************************************* ************
duty Var word ' Create adval to store result
freq var word
is1 var word ' Current sense 1
is2 var word ' Current sense 2
temp var word
temp1 var word
tempb var byte
seconds var word
ScaledDelay var word

in1 var latc.4
inh1 var latc.5
in2 var latc.6
inh2 var latc.7

mode var porte.1
start var porte.0

lcdout $fe,$1

goto over_ISR

Timer0_ISR: 'Timer 0 overflow interrupt every 1msec
if seconds>100 then
Adcin 0, duty ' Read the first ADC channel ************************************************** **** was 0
duty=duty/4 ' scale for 10bit PWM
if duty<10 then duty=10

tempb=duty/10 ' scale to 0-100%
if tempb>100 then tempb=100

adcin 1, freq

if freq<68 then freq=136
freq=freq/68
endif

if seconds<1000 then
seconds=seconds+1
else
seconds=0
Timer0=0 'Stop timer0
TMR0H=$C1 'Load Timer 0 with start value $C187
TMR0L=$87 'to count up 16000 steps until rollover
Timer0=1 'Start timer0
'toggle portc.5 'toggle every second
endif
adcin 27,is1
adcin 26,is2
if !start then lcdout $fe,$80,"DC%:",#tempb," ",$fe,$88,"f:",#freq," ",$fe,$c0,"Half-B"," ",#ScaledDelay," "
@ INT_RETURN

over_ISR:
pause 500
Lcdout $fe, 1 ' Clear the LCD

'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, _Timer0_ISR, PBP, yes
endm
INT_CREATE
ENDASM

@ INT_ENABLE TMR0_INT

mainloop:
Timer0=1 'start timer 0

Lcdout $fe,$80,"DC%:",#tempb," ",$fe,$88,"f:",#freq," ",$fe,$c0," "

if !start then
if !mode then
gosub halfbridge
goto mainloop
low in1 ' Stop NCO, PWM
low in2
endif
endif

if !start then
if mode then
gosub fullbridge
goto mainloop
low in1 ' Stop NCO, PWM
low in2
endif
endif


Goto mainloop ' Do it forever

halfbridge:
pause 100 'debounce
while !start
ScaledDelay=500/freq
CCPR1L=duty.byte0 ' update PWM
CCPR1H=duty.byte1
RC5PPS=%00001001 'enable PWM on RC1, pin 16
high in1
low in2
high inh2
pause ScaledDelay
high in2
pause ScaledDelay
wend
low in1
low in2
low inh2
CCPR1L=0 ' Reset PWM
CCPR1H=0

return

end

Jerson
- 30th May 2025, 03:04
First thing that seems unusual to me is LCDOUT inside the ISR handler. That is something I would not do.
Secondly, there is a statement if freq < 68 then freq = 136 followed by freq = freq/68. As this is happening every 100mSec, could it be that freq is changing frequently leading to ScaledDelay jumping around?
Then there is goto mainloop followed by low in1, low in2. These statements will never execute as they come after goto mainloop.

My guess is that the LCDOUT inside the ISR and also in mainloop could be the cause of your trouble.

Ioannis
- 30th May 2025, 22:28
Thanks Jerson.

At the moment it looked OK to have the LCDout inside the regularly called ISR, as it updatetd the LCD often. If the freq is low enough 1-2 Hz, it updates every second the LCD because of the Pause commands.

Anyway, I moved the LCDout inside the Halfbridge sub and corrected the IF statement (<68 then freq=136). This helped much but not completely.

The final solution was to remove the ISR alltogether. Seems there is something fundamentally wrong with my ISR setup.

Ioannis

HenrikOlsson
- 31st May 2025, 10:55
In the ISR you have this:

if seconds<1000 then
seconds=seconds+1
else
seconds=0
Timer0=0 'Stop timer0
TMR0H=$C1 'Load Timer 0 with start value $C187
TMR0L=$87 'to count up 16000 steps until rollover
Timer0=1 'Start timer0

To me, this looks a bit strange - you're only reloading the TMR0 registers once every 1000 interrupts meaning that only the "first" period will be 1ms, then there will be 999 periods where the timer will freerun all the way from 0 to rollover.