PDA

View Full Version : Multiple PWM and port C



Scampy
- 11th December 2013, 11:30
Hi,

Still working on my aquarium lighting controller as I've discovered an issue with using the hardware PWM on the 18F4520. I've opted to use Darrels multi-SWPM files, and after a littler re-write the code compiles and runs, but with some strange quirkyness that I can't seem to get my head round.

As I already have PCB's made I need to keep the two PWM pins on port C1 and C2. Now when I use these, the RTC clock displays a stupid time of 48:85 and everything locks up as the clock is not out putting the correct time. If I change the multi-spwm pins to port D1 and D2, the clock runs fine with the correct time. Here is the settings I've used for Darrels include file



define SPWMFREQ 100 ' PWM frequency in Hz

SPWM1PIN VAR PORTC.1 ' SPWM channel 1
define SPWM1VAR _B_PWM

SPWM2PIN VAR PORTC.2 ' SPWM channel 2
define SPWM2VAR _W_PWM


I've obviously commented out the port settings for the hardware PWM register


'************************************************* ******************************
'Port and Register settings
'************************************************* ******************************

'CCP1CON = %00001100 'Set CCP1 to PWM
'CCP2CON = %00001100 'Set CCP2 to PWM
TRISA = %11101111
TRISB = %00000011
TRISD = %00000011
T0CON = %11000111


I basically need to configure portC so that C0, C1 and C2 are digital, C3 and C4 are used for the RTC (SDA and SCL), but I'm struggling

HenrikOlsson
- 11th December 2013, 13:08
Hi,
I don't know much about I2C but I suspect that the issue you're having could be timing related. If you're using the PBP commands for I2C then then the communication is bit-banged and software timed. Darrels SPWM routines uses interrupts to do its thing which will disturb the timing of the I2C communication.

I'm curious what the issue with using hardware PWM actually means. Since the hardware is built to use the CCP modules I'd do everything I possibly could to actually make use of them instead of reverting to bit-banging PWM.

/Henrik.

Scampy
- 11th December 2013, 13:40
Hi Henrik,

The issue with the hardware PWM was that it doesn't produce a nice square wave, and even at 100% (255) duty is still sending a signal rather than full line level. The net result was that the LED drivers were running around 60% when the PIC was outputting full duty cycle. Using Darrels software PWM I get a nice square wave, which at 0 duty cycle I get 0 volts, at 255 duty I get 5v and full Mark to Space ratio. (ie a solid line with no pulses), which is what you would expect.

I don't think it's a timing issue as I've knocked up a version where the RTC works, and port C1 and C2 drive the LEDs, just when I copy that code to my main program, comment out the reference to CCP registers the resulting HEX causes the clock to function as described.

My only option is to manually modify the PCB to use port E1 and E2....

Scampy
- 11th December 2013, 14:17
Interestingly, I have the temp sensor (18B20) on port RA5. If I use RA4 and RA7 as the PWM pins the temperature reading goes heywire, displaying random temperatures like 163C but is often trying to over write the display. With RA4 and RA7 set as the pins for pWM, the clock on C3 and C4 runs fine....

HenrikOlsson
- 11th December 2013, 15:42
OK, so then it's some kind of interference between the SPWM routines and the rest of the program, perhaps a read-modify-write issue, I don't know. But then you say that you had a version with both SPWM and I2C on the same port (different pins of course) which DID work so I don't know. Hopefully Darrel or someone else who's been using the routines in quesiton will jump in.

Back to the hardware PWM.... Did you set the registers manually or did you use the HPWM command?
If you set the registers manually then the number of bits of resolution you get depends on the frequency you select so a dutycycle value of 255 doesn't neccesarily mean 100% - it depends.
If, on the other hand, you DID use the HPWM command then you should have got 100% with a duty of 255 - given you had told the compiler the correct operating frequency, ie DEFINE OSC xx.

I still think you should concentrate on getting the CCP modules to do the PWM for you. Post the code for that and I'll take a look.

/Henrik.

Scampy
- 11th December 2013, 15:55
Well I just re-loaded the test code that uses port C for both clock and PWM pins and that appears to do the same thing, with 10:10 shown as the time. Mind you I've been cutting and pasting bits of code from one to the other to try and resolve this.

When using CCP modules I simply used CCP1CON = %00000000 and CCP2CON = %00000000 to set the register and then used PBP HPWM command to drive the pins....

I'll drop you a PM with the code....

HenrikOlsson
- 11th December 2013, 16:50
Hi,
Took a quick look at the code you PM'd me and found this:

'If light=1 then ' If the variable is 1 then output full PWM to lights
' hpwm 1,255,200
' hpwm 2,255,200
'endif
'If light=0 then ' If the variable is low then set value to 0 an turn off the lights
' hpwm 1,0,200
' hpwm 2,0,200
'endif
If this is where you're trying to set 100% dutycycle but ends up with a "jumpy" signal not at 100% then the problem is most likely that you're trying a frequency (200Hz) far below the specified minimum. If you look at the manual you'll see that for a 18F device running at 20MHz the minimum frequency is 1221Hz.

The only other place in the code where HPWM was used had a frequency of 5kHz so that should've worked - did it?

/Henrik.

Scampy
- 11th December 2013, 16:53
Changing ADCON0 to a value of 7 and changing the SW PWM pins to C1 and C2 made the clock to something, but it's still not running. The clock displayed 45:00 and then counted up in seconds (45:01, 45:02 etc) until it reach 14:10 and then displayed the 45:51. It remained displaying this "time", then changed to 45:52 a minute later, followed by 45:53 etc but there was no change in the case and the LEDs didn't light.

Not sure if changing ADCON0 to 7 (all digital) had a bearing on things

Scampy
- 11th December 2013, 16:58
Hi,
Took a quick look at the code you PM'd me and found this:

'If light=1 then ' If the variable is 1 then output full PWM to lights
' hpwm 1,255,200
' hpwm 2,255,200
'endif
'If light=0 then ' If the variable is low then set value to 0 an turn off the lights
' hpwm 1,0,200
' hpwm 2,0,200
'endif
If this is where you're trying to set 100% dutycycle but ends up with a "jumpy" signal not at 100% then the problem is most likely that you're trying a frequency (200Hz) far below the specified minimum. If you look at the manual you'll see that for a 18F device running at 20MHz the minimum frequency is 1221Hz.

The only other place in the code where HPWM was used had a frequency of 5kHz so that should've worked - did it?

/Henrik.

Hi,

That section had been commented out from when I was using the hardware modules. It was intended as a manual over-ride so that I could turn the lights on or off via the push of a button. I never ran the module at high frequencies as the LED driver requires a PWM frequency of 100 hz - 1khz and at 1 Khz they resonated with a high pitched sound.

The original code had


'************************************************* ******************************
'Send pulses to drivers

hpwm 1,W_PWM,200
hpwm 2,B_PWM,200

'************************************************* ******************************


Where W_PWM and B_PWM increased from 0 to 255 or decreased from 255 to 0 to fade the LEDs up and down

Scampy
- 11th December 2013, 18:28
I've just tried cutting and pasting the code into a new page and renamed it - complied and loaded and got the same results when using C1 and C2 as the PWM pins. If I comment out the include "Multi_SPWM.pbp" the program runs fine, but I obviously have no outputs from the two pins.

So maybe you're right Henrik, in that there is some clash with the timing / or i2c bus ???

HenrikOlsson
- 11th December 2013, 18:45
Hi,
Since it seems to work when you're using SPWM on one port (PortB for example) while the I2C is on another (PortC) I don't think it's a timing thing.
Since it does NOT seem to work when the SPWM is on the SAME port as the I2C I think it's some other sort of interference where the SPWM is messing with the I2C pins, possibly due to R-M-W but I don't know for sure.

As for the hardware PWM....


The original code had

'************************************************* ******************************
'Send pulses to drivers

hpwm 1,W_PWM,200
hpwm 2,B_PWM,200

'************************************************* ******************************

Well, then that IS the problem you're having - you're trying to run it at TO LOW frequency, which was the point I was trying to make.
At 20MHz oscillator frequency there is no way to actually get 200Hz from the CCP module, the lowest possible frequency is 1221Hz.

/Henrik.

Scampy
- 11th December 2013, 19:07
Ok I've tried a different approach. I noticed that Darrel has revised his multiple PWM Routine Called SPMW_INT rather then the Multi_SPWM So I modified a fresh copy of the code, included that file and the DT_INTS-18 file and the thing compiled. Loaded it to the chip and both the TEMP and CLOCK are acting up. The temp is shown as 163c and the clock as 45:85.

Here's the main part of the revised code



ASM
__CONFIG _CONFIG1H, _OSC_HS_1H
__CONFIG _CONFIG2L, _PWRT_ON_2L
__CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_512_2H
__CONFIG _CONFIG3H, _MCLRE_ON_3H & _LPT1OSC_OFF_3H & _PBADEN_OFF_3H
__CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
ENDASM

INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "SPWM_INT.bas" ; Software PWM module

DEFINE SPWM_FREQ 200 ; SPWM Frequency
DEFINE SPWM_RES 256 ; SPWM Resolution

ASM
SPWM_LIST macro ; Define Pin's to use for SPWM
SPWM_PIN PORTC, 1, _B_PWM ; and the associated DutyCycle variables
SPWM_PIN PORTC, 2, _W_PWM ; Notice the underscore before variables

endm
SPWM_INIT SPWM_LIST ; Initialize the Pins
ENDASM

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, SPWMhandler, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts


INCLUDE "LCDbar_INC.bas" ' Include the BARgraph routines


DEFINE LCD_DREG PORTB ' LCD Data port
DEFINE LCD_DBIT 0 ' starting Data bit (0 or 4)
DEFINE LCD_EREG PORTB ' LCD Enable port
DEFINE LCD_EBIT 5 ' Enable bit (on EasyPIC 5 LCD)
DEFINE LCD_RSREG PORTB ' LCD Register Select port
DEFINE LCD_RSBIT 4 ' Register Select bit (on EasyPIC 5 LCD)
DEFINE LCD_BITS 4 ' LCD bus size (4 or 8 bits)
DEFINE LCD_LINES 4 ' number of lines on LCD
DEFINE LCD_COMMANDUS 2000 ' Command delay time in us
DEFINE LCD_DATAUS 50 ' Data delay time in us

DEFINE OSC 20 ' 18F4520, 20mhz crystal
ADCON1 = $0F
clear

'************************************************* ******************************
'DS18B20 temp probe setting
'************************************************* ******************************

DQ VAR PORTA.5 ' One-wire data pin
temperature VAR WORD ' Temperature storage
count_remain VAR BYTE ' Count remaining
count_per_c VAR BYTE ' Count per degree C

'************************************************* ******************************
'Port and Register settings
'************************************************* ******************************

TRISA = %11101111
TRISB = %00000011
TRISD = %00000011
T0CON = %11000111

ADCON0 = %00000000; // AD converter module disabled
ADCON1 = %00001111; // All Digital
ADCON2 = %00000000; //
CMCON = 7

'************************************************* ******************************
' Data presets
'************************************************* ******************************
data @0
data 00 'Blue fade IN duration hours
data 5 'Blue fade IN duration minutes
data 00 'Blues fade OUT duration hours
data 45 'Blue fade OUT duration minutes
data 00 'Whites fade IN duration hours
data 7 'Whites Fade IN duration MINS
data 00 'Whites Fade OUT duration HOURS
data 20 'Whites Fade OUT duration MINS
data 255 'Blue MAX Intensity %
data 255 'Whites MAX Intensity %
data word 840 'Blue ON time 14:00
Data word 840 'Whites ON time 14:00
data word 1200 'Blue OFF time 20:00
Data word 1200 'White OFF time 20:00
Data word 1200 'Sump light on time 20:00
Data word 1200 'Sump light off time 8:00


'************************************************* ******************************
' Variables
'************************************************* ******************************

fadesetHR VAR WORD[2]
fadesetHR1 VAR fadesetHR[0] 'blue fade in hour
fadesetHR2 VAR fadesetHR[1] 'White fade in hour

fadesetMN VAR WORD[2]
fadesetMN1 VAR fadesetMN[0] 'blue fade in minutes
fadesetMN2 VAR fadesetMN[1] 'white fade in minutes

fadeoutHR VAR WORD[2]
fadeoutHR1 VAR fadeoutHR[0] 'blue fade out hour
fadeoutHR2 VAR fadeoutHR[1] 'white fade out hour

fadeoutMN VAR WORD[2]
fadeoutMN1 VAR fadeoutMN[0] 'blue fade out minute
fadeoutMN2 VAR fadeoutMN[1] 'white fade out minutes

lightsetHR VAR word[2]
lightsetHR1 VAR lightsetHR[0] 'blue on time hour
lightsetHR2 VAR lightsetHR[1] 'white on time hour

lightsetMN VAR word[2]
lightsetMN1 VAR lightsetMN[0] 'blue on time minutes
lightsetMN2 VAR lightsetMN[1] 'white on time minutes

lightoffHR VAR word[2]
lightoffHR1 VAR lightoffHR[0] 'blue off time hour
lightoffHR2 VAR lightoffHR[1] 'white off time hour

lightoffMN VAR word[2]
lightoffMN1 VAR lightoffMN[0] 'blue off time minutes
lightoffMN2 VAR lightoffMN[1] 'white off time minutes


DecButton var PORTA.0 ' Press to Decrement Button
SetButton var PORTA.1 ' Press to Set/memorise Button
IncButton var PORTA.2 ' Press to Increment Button

OnButton var PORTA.0 ' Press to Decrement Button
OffButton var PORTA.2 ' Press to Increment Button

H_butt VAR PORTA.2 'hour increase
M_butt VAR PORTA.0 'minutes increase
S_butt VAR PORTA.1 'set / memorise

Counter1 var word 'used to store the current time as a digit. Counts minutes from 0000 at midnight

Blue_on_Time var word 'stores the blue on time as a digit in minutes, eg 14:00hrs = 840
Blue_off_Time var word 'stores the blue off time as a digit in minutes, eg 14:00hrs = 840
White_on_Time var word 'stores the white on time as a digit in minutes, eg 14:00hrs = 840
White_off_Time var word 'stores the white off time as a digit in minutes, eg 14:00hrs = 840

white_delay_in var byte 'stores the white fade in pule in seconds
blue_delay_in VAR byte 'stores the blue fade in pule in seconds
white_delay_out var byte 'stores the white fade out pule in seconds
blue_delay_out VAR byte 'stores the blue fade out pule in seconds

W_Min var byte 'Min Light value - Whites
W_Max var byte 'Max Light value - Whites
B_Min var byte 'Min Light value
B_Max var byte 'Max Light value

Old_B_Max var byte
Old_W_Max var byte

W_PWM var word 'PWM Variables where the current output values are stored - Whites
B_PWM var word 'PWM Variables where the current output values are stored - Royal Blues

old_ss_blue var byte 'records the previous second in blue fade in
old_ss_white var byte 'records the previous second in white fade in

option var byte 'menu option, used to choose which menu option is required

Viv var byte 'used to select the channel the menu selection applies to
maxbright var byte 'general variable used to set the max brighness for each channel in menu option

fn var byte 'general variable to switch between channels in menu options
Hours var byte 'used in menu options to set hours for each channel
Minutes var byte 'used in menu options to set minutes for each channel
light var byte

Sumplighton Var word 'counter variable for sump on time
Sumplightoff Var Word 'counter vairable for sump off time
Sump_light Var PORTA.4 'sump light pin
sumponHR VAR byte 'sump light on Hour
sumponMN var byte 'sump light on Minutes
sumpoffHR var byte 'sump light off Hours
sumpoffMN var byte 'sump light off Minutes

daycount var byte

TimeH var byte 'variable to store Hours
TimeM var byte 'variable to store Minutes
SS VAR Byte 'variable to store Seconds

RTCsec var byte 'RTC Seconds
RTCMin var byte 'RTC Minutes
RTCHour var byte 'RTC Hours
SetMN var byte 'Used to set time Minutes
SetHR var byte 'Used to set time Hours
SetSS var byte 'Used to set time Seconds

SCLpin var PORTC.3 'RTC pin - clk
SDApin var PORTC.4 'RTC pin - data

CounterA var byte 'General purpose Variable
CounterB var byte 'General purpose Variable
CounterC var byte 'General purpose Variable
CounterD var byte 'General purpose Variable

FlashStar VAR BIT

Blue_Day_Cycle var word 'Store for which part of the blue day cycle we are in
White_Day_Cycle var word 'Store for which part of the white day cycle we are in


DAWN con 0 'Constants for the current running mode cycle for the lights
DAY con 1
DUSK con 2
NIGHT con 3

'************************************************* ******************************
;Initialization

LCDOUT $FE,1:FLAGS=0:PAUSE 250:LCDOUT $FE,1:PAUSE 250 ' Initialize LCD
LCDOUT $FE,1
lcdout $FE,$C0," Firmware v1.07 "
pause 2000 'wait 2 seconds so they can see it
lcdout $FE,1 'Clear the screen

Gosub read_eprom 'read in presets for fade in durations and brighness

blue_delay_in = (((fadesetHR[0]*60)+fadesetMN[0])*60)/255 'takes hours and minutes, converts to minutes, then converts to seconds
white_delay_in = (((fadesetHR[1]/60)+fadesetMN[1])*60)/255 'takes hours and minutes, converts to minutes, then converts to seconds
blue_delay_out = (((fadeoutHR[0]/60)+fadeoutMN[0])*60)/255 'takes hours and minutes, converts to minutes, then converts to seconds
white_delay_out = (((fadeoutHR[1]/60)+fadeoutMN[1])*60)/255 'takes hours and minutes, converts to minutes, then converts to seconds

Option = 1 'sets the menu option default as 1 (set time)
daycount=0 'used in sumplight routine to check if gone passed midnight

Sumplightoff =1439
Sumplighton =1439 'sumplight - values used to match counter1 for on off times

setHR = 13 'initial time following programming or re-boot if RTC not battery backed up
setMN = 59

'convert initial time to BDC and write it to the DS1307
CounterA=SetMN
Gosub ConvertBCD
RTCMin=CounterB

CounterA=SetHR
Gosub ConvertBCD
RTCHour=CounterB

I2Cwrite SDApin,SCLpin,$D0,$00,[RTCSec,RTCMin,RTCHour]



'************************************************* ******************************
'************ Main Program Loop ***************
'************************************************* ******************************

Main:

If SetButton=0 then 'if presed jump to the menu
goto mainmenu
endif

'************************************************* ******************************
' check for manual override of the lights
If H_butt = 0 then ' if pressed then change state of varible to 1
Light=1
endif

If M_butt = 0 then ' if pressed then change state of varible back to 0
Light=0
endif
'************************************************* ******************************
'clock routine

I2CREAD SDApin,SCLpin,$D0,$00,[RTCSec,RTCMin,RTCHour] ; read DS1307 chip

timeH=(RTCHour>>4) 'convert the BCD format of the hours register and store in variable timeH
timeH=(timeH &$03)*10
timeH=timeH+(RTCHour&$0F)

timeM=(RTCMin>>4) 'convert the BCD format of the mins register and store in variable timeM
timeM=(timeM &$07)*10
timeM=timeM+(RTCMin&$0F)

ss=(RTCSec>>4) 'convert the BCD format of the sec register and store in variable ss
ss=(ss &$07)*10
ss=ss+(RTCSec&$0F)

Counter1 = (TimeH *60)+ TimeM 'take hours and multiply it by 60 then add odd minutes to get the total minutes into counter1

LCDOut $FE,$D4+15,#TimeH DIG 1,#TimeH DIG 0,":",#TimeM DIG 1,#TimeM DIG 0


'************************************************* ******************************
' check to see if the sump light should be on or off

If daycount = 0 THEN ' by default daycount is 0
If Counter1 => sumplighton Then ' if the counter matched the sump light on time
high sump_light ' then make the pin high and
daycount = 1 ' set the day count to 1
ENDIF
ENDIF

IF daycount = 1 THEN ' if the daycount is 1 and
If Counter1 = sumplightoff Then ' conuter matches sump light off time
low sump_light ' then make the pin low and
daycount = 0 ' reset daycount back to 0
ENDIF
ENDIF

'************************************************* ******************************
'Case Cycle logic

If Counter1 < Blue_on_Time then
Blue_day_cycle = NIGHT
endif

if counter1 > blue_on_time and Counter1 > blue_off_Time and B_PWM > B_Min then
Blue_day_cycle = DUSK
endif

if counter1 => blue_on_time and Counter1 < blue_off_Time and B_PWM < B_MAX then
Blue_day_cycle = DAWN
endif


If Counter1< White_on_Time then
White_day_cycle = NIGHT
endif

if counter1 > white_on_time and Counter1 > white_off_Time and W_PWM > W_Min then
White_day_cycle = DUSK
endif

if Counter1 => white_on_time and Counter1 < white_off_Time and W_PWM < W_MAX then
White_day_cycle = DAWN
endif

'************************************************* ******************************
'BLUE daily cycle

select case Blue_Day_Cycle

case DAWN
lcdout $FE,$80+15,"DAWN "
if ss//blue_delay_in = 0 then
if ss != old_ss_blue then
B_PWM=B_PWM+1
old_ss_blue=ss
endif
endif
if B_PWM = b_max then
Blue_Day_Cycle = DAY
endif

case DAY
lcdout $FE,$80+15,"DAY "
if B_max < B_PWM then
B_PWM=B_PWM - 1
endif
if counter1 =blue_off_time then
Blue_day_cycle = DUSK
endif

CASE DUSK
lcdout $FE,$80+15,"DUSK "
if ss//blue_delay_out= 0 then
if ss != old_ss_blue then
B_PWM=B_PWM-1
old_ss_blue=ss
endif
endif
if B_PWM = B_MIN then
Blue_Day_Cycle = NIGHT
endif

case NIGHT
lcdout $FE,$80+15,"NIGHT"
B_PWM=B_min
end select

'************************************************* ******************************
'WHITE daily cycle

select case White_Day_Cycle

case DAWN
lcdout $FE,$C0+15,"DAWN "
if ss//white_delay_in= 0 then
if ss != old_ss_white then
W_PWM = W_PWM+1
old_ss_white=ss
endif
endif
if W_PWM = W_max then
White_Day_Cycle = DAY
endif

case DAY
lcdout $FE,$C0+15,"DAY "
if W_max < W_PWM then
W_PWM=W_PWM - 1
endif
if counter1 =white_off_time then
White_day_cycle = DUSK
endif

CASE DUSK
lcdout $FE,$C0+15,"DUSK "
if ss//white_delay_out= 0 then
if ss != old_ss_white then
W_PWM=W_PWM-1
old_ss_white=ss
endif
endif
if W_PWM = W_min then
White_Day_Cycle = NIGHT
endif

case NIGHT
lcdout $FE,$C0+15,"NIGHT"
W_PWM=W_min
end select

'************************************************* ******************************
'tidy up the display for the current percentage to remove stray zero's

If (B_PWM * 100)/255 = 100 then
lcdout $FE,$80,"BL ",$FE,$80+3,dec3 (B_PWM *100)/255,"%"
endif

If (B_PWM * 100)/255 =0 or (B_PWM * 100)/255 <10 then
lcdout $FE,$80,"BL ",$FE,$80+3,dec1 (B_PWM *100)/255,"% "
endif

if (B_PWM * 100)/255 >=10 and (B_PWM * 100)/255 <100 then
lcdout $FE,$80,"BL ",$FE,$80+3,dec2 (B_PWM *100)/255,"% "
endif

If (W_PWM*100)/255 >= 100 then
lcdout $FE,$C0,"WT ",$FE,$C0+3,dec3 (W_PWM *100)/255,"%"
endif

If (W_PWM * 100)/255 <=0 or (W_PWM * 100)/255 <10 then
lcdout $FE,$C0,"WT ",$FE,$C0+3,dec1 (W_PWM *100)/255,"% "
endif

if (W_PWM * 100)/255 >=10 AND (W_PWM * 100)/255 <100 then
lcdout $FE,$C0,"WT ",$FE,$C0+3,dec2 (W_PWM *100)/255,"% "
endif
'************************************************* ******************************
'Get and display the temperature

OWOUT DQ, 1, [$CC, $44] ' Start temperature conversion
OWOUT DQ, 1, [$CC, $BE] ' Read the temperature
OWIN DQ, 0, [temperature.LOWBYTE, temperature.HIGHBYTE]
temperature = temperature */ 1600
lcdout $FE,$D4+0,"TEMP ",DEC(temperature / 100),$DF,"C"
'************************************************* ******************************
'generate bar graph on LCD

; syntax- BARgraph Value, Row, Col, Width, Range, Style
@ BARgraph _B_PWM, 1, 8, 6, 255, lines
@ BARgraph _W_PWM, 2, 8, 6, 255, lines


GOTO Main


Darrels code seems to allow frequencies of 100hz which makes this ideal.... if it can be made to work

I appreciate all your help....Hopefully Darrel can shed some light

Oh and meant to add that it runs really slowly (displays the firmware splash screen for around fifteen seconds rather than the three or so

HenrikOlsson
- 11th December 2013, 20:04
Hi,
The reason it runs slow is due to the interrupt driven PWM routines. You have a PWM frequency of 200Hz and a resolution of 256 steps, this results in an interrupt frequency of 51200Hz.
According to Darrels page (if I'm on the right one) each "PWM-channel" needs 20 instructions - in your case 51200 * 20 * 2 = 2,048,000 instructions per second, just for running the 2 PWM channels. At 20MHz there's 5,000,000 instructions per second to play with which means that 40% of the processors time is spent running the PWM.

You tell PBP that you're running at 20MHz but then the assembly interrupts silently eats away 40%.

In this case each and every Hz you decrease the PWM frequency will give more time to the actual PBP program, if 100Hz is "all" you need then don't try running it at 200Hz. But again, it doesn't seem to be the timing per se that makes it NOT work since it using different ports for the PWM and I2C works.

/Henrik.

Scampy
- 11th December 2013, 20:55
Thanks for the explanation...

I think I'll go back to using port D for the outputs and revert back to the mulit_swpm file. Not ideal, as I'll have to modify the PCB, but at least it works without the delays or screwing up the clock etc. If I get chance I'll try this on the old 16F877A chip rather than an 18F to see if this issue is chip related...

Scampy
- 11th December 2013, 23:04
I've recorded the wave form when using the hardware PWM modules on the chip to explain the issue I'm getting.


http://youtu.be/hzfXvv-gNvc

If you compare this to using the multi_swpm file and port D you notice there are loads of spikes in the HWPM signal and some harmonics ? - the amplitude is also a lot less (I had to increase the volume for the HWPM to get a similar trace)


http://youtu.be/trpTvKC7BqQ

HenrikOlsson
- 12th December 2013, 06:15
As I've said a couple of times now:
You can not run the hardware PWM at a frequency below 1221Hz - it's not a bug in PBP and not a hardware issue with the PIC or the circuit, it's just the way it is.

The reason is because TMR2, which is used for the PWM timebase is 8 bits wide and has a prescaler with a maximum ratio of 1:16. At 20MHz the timer ticks at 5MHz, so 5,000,000/256/16=1220.7Hz. If you try anything lower than that it will not work properly and I'm pretty sure that's what you're seeing when trying to run it at 200Hz.

To prove or disprove, try it again at 1500Hz and see if the waveform looks better. I understand that it won't work in your particular application due to the LED drivers but it'll show that actual problem is that you're trying to run the PWM at a frequency (200Hz) which the module is incapable of producing.

/Henrik.

richard
- 12th December 2013, 06:53
all the spwm interrupts will muck up the i2c and onwire timing . you will probably need to disable the ints during the actual data transfers

HenrikOlsson
- 12th December 2013, 11:00
Hi Richard,
That was my initial thought as well but then Scampy wrote:

Interestingly, I have the temp sensor (18B20) on port RA5. If I use RA4 and RA7 as the PWM pins the temperature reading goes heywire, displaying random temperatures like 163C but is often trying to over write the display. With RA4 and RA7 set as the pins for pWM, the clock on C3 and C4 runs fine...
Which indicates that as long as the PWM is not on the same port as the I2C it does seem to work - only when the PWM and I2C (or 1Wire) is on the same port does it act up.
If it was a timing issue then I can't see how moving the I2C to a different port than the PWM would make it work. I'm leaning more towards some kind of port or tris register overwrite causing the issue, perhaps a R-M-W but of course I can't say for sure.

/Henrik.

richard
- 12th December 2013, 12:04
hi henrick
it could be that the port value gets changed by the int routine between a read modify write action in the i2c or onewire routines, or vice versa
simply stetting the timer int off before the i2c and one wire transactions and restoring it afterwards should be easy enough to try . if that works its an easy fix

HenrikOlsson
- 12th December 2013, 12:28
Hi,
I agree, it's easy to try and and an easy fix provided it doesn't result in any obvious glitches or blinking effect on the LEDs being driven by the PWM.
But why would the PWM routine change bits that it (the PWM routine) has nothing to do with. Something is going on for sure but I can't really figure out a real good reason.

/Henrik.

Scampy
- 12th December 2013, 14:07
OK guys you've lost me.

I think the work around for now is to simply use pins D1 and D2 as the output and solder links on the PCB - This way I get a working solution of true square wave of 0-5v running at a frequency that suits the LED drivers, and code that runs at a suitable speed.

Thanks again for all your input....

Demon
- 12th December 2013, 14:45
Have you tested different caps to filter that noise on square waves?

Robert

Scampy
- 15th December 2013, 16:24
Ok, for the past few days I've been running the code on the development board using D2 and D3 as the output pins for the PWM - all was fine so I placed the chip in the controller and over the weekend it's been running fine, and with the added bonus that the LDD LED drivers don't sing like they used to when using the hardware generators on the PIC.

So I've now started to add in the next module for the project, serial communications. Thanks to Robert's post in my other thread I've used MisterE's tool to generate the port definitions etc, and after a slight hardware issue with the USB/serial cable used a simple echo program to test the comms - it worked fine, using the Comms tool in Microcode Studio I was able to connect to the port, and whatever I sent from the PC was echoed back in the RX panel...I then opened the current working version of my code and simply inserted the line


Hserout ["Blues ",DEC(B_PWM * 100)/255, 13, 10] ' Send text followed by carriage return and linefeed

which should simple send the value of B_PWM as a percentage to the PC. However when I compiled the code and ran it, then set the clock to the time the lights were on, the PWM remained at 0 and didn't increase. The RTC ran, and the menu options worked so the code was looping, but for some reason I never got an output from the software pins or the LCD. If I commented out the Hserout line the code works perfectly.

It seems another conflict when running DT's multi_pwm with port C, and again its coms related.

Scampy
- 15th December 2013, 16:35
Uhmmmm
Adding a pause 1000 after the line seems to of resolved the issue (head scratch !!!)