# Four independent PWM signals in software

Status
Not open for further replies.

#### atferrari

##### Well-Known Member
18F family - Assembler.

I need four independently-variable duty cycle PWM signals destined to generate each one a stable control voltage with 10 bit resolution.

Chips like 18F4550 have 4 PWM outputs but they are aimed to drive H bridges so cannot be used as I need.

Understand the solution is to do it in software. Have searched but could not find any post directly related to my problem.

I have the feeling that ruling out ANY glitches should be the hardest part to solve, if at all possible.

Ideas anyone?

Gracias.

#### eng1

##### New Member
Are you saying that you require PWM or can you use alternative solutions?
I am thinking of two MCP4922. You can control the output voltage via SPI by setting the internal registers of the DACs (this is equivalent to setting the duty cycle of PWM signals with your control variables).
I've used the 4921/22 with good results.

Last edited:

#### nickelflippr

##### Member
Try looking at the 18f4431 for four independent hardware PWM, and four complimentary (i.e. half bridges).

#### Mike - K8LH

##### Well-Known Member
Hi Agustín,

Please tell us what is the target PWM period or frequency that you're shooting for? This will help us determine the type of solution that may work best for you.

Regards, Mike

#### atferrari

##### Well-Known Member
Thanks to you all for replying. I go in order:

eng1:
I prefer to use PWM, if at all possible, to keep the parts count low. But eventually could resort to some kind of DAC.

nickelflippr:
It seems (just seems) overkill but, why not?. Should check local availability.

Mike, K8LH:
LTSpice says that 20KHz could be good for me. I do not discard using something slower / faster if software implementation demands. Would use 4 MHz xtal if at all possible.

Gracias again.

#### Mr RB

##### Well-Known Member
What is the PWM voltage controlling? How fast does the PWM voltage need to change?

#### kchriste

##### New Member
Forum Supporter
LTSpice says that 20KHz could be good for me. I do not discard using something slower / faster if software implementation demands. Would use 4 MHz xtal if at all possible.
Even with hardware PWM, you need at least a 20.5 Mhz clock for 20Khz PWM with 10bit resolution.

#### atferrari

##### Well-Known Member
Lower frequency then...

Mr RB:
Changes at the pace imposed by the user and always one output at a time. No worries here. My sole concern is how to generate them.

kchriste:
Yes. Last night, revising the manual of the 18F4550 found that the table shown there is calculated for a 40 MHz xtal. That makes for lower frequencies than I elected at first.

K8LH:
Tested with LTSpice and I would go then with a frequency around 3900Hz.

General comments:

I expect to have the micro focused on generating those four PWM signals, carrying out the ancillary duties (keyboard, display, etc) at ease.

My search in Google did not come with too many concrete things that I could use a starting point. Not too much time here to work out something by myself. Still travelling like a mad.

There are moments that I am about to give up and go for the DACs from MCP or even Maxim.

Thanks for your replies.

Last edited:

#### atferrari

##### Well-Known Member
Cutting the Gordian knot

After checking what was available locally, costs and available time I decided to buy the 18F4431 (some 10 USD on the counter). It was the cheapest / most feasible option.

I still think that some limited range PWM could be possible in software if PART of the whole range is used. I would like to try that in the future, just as a proof of concept.

BTW, anyone willing to give ideas about my initial request will be still welcome and heard.

Gracias to all replying!!

Last edited:

#### Mr RB

##### Well-Known Member
Ok, if you don't need a fast rate of change of the voltages, you can use a slow PWM freq and larger RC filtering.

Generate each PWM signal in sequence. This limits you to about 0v to 1v range for each voltage output.

1. on TMR1 overflow; set the PWM pin (make / edge)
2. use the capture compare int to see when the pwm period ends, then clear all PWM pins (make \ edge).

Then on the next TMR1 overflow do the next PWM value, so the 4 pwm pulses are made 1 at a time.

This will give you the full 16bit PWM resolution, but the max voltage of each PWM will be about 1.2v.

Does that help?

#### atferrari

##### Well-Known Member
Yes Mr RB,

I think it is a simpler and feasible way to go. Thanks.

Last edited:

#### jeremygaughan

##### New Member
I don't know if this will help you do what you want but It is possible to run a lot of PWM signals in this manner. I have a sample program here that runs two PWM's using the data it gets from two separate A/D conversions. The way to make more PWM signals is simply add more channels to the "pwm" part of the program. To change the frequency you change the TMRO value or prescaler. To change the period you change the values of the folder period. (also some adjustments might need to be made to your channel values.)

The way it works is TMRO interrupts and adds one to your period value.
Then it adds your channel value to the period value.
If flag tripped turn off that pin.
If flag not tripped turn on that pin.
It goes through the channels and checks them all.
Last, when the period overflows it resets everything and starts counting again.

This allows you to keep all your PWM stuff free from the rest of your program. Also, it gives you pretty good resolution. However, it seems like you need a bit more resolution. I'm sure you can fix that with a tweek to the period counter and the channel values. The problem is it takes 20 to 30 commands every interrupt.
Good luck and I hope this helps in some way.

Code:
;learning to do pwm with tmro 12f675

list P=12f675
#include <p12f675.inc>
__config _INTRC_OSC_NOCLKOUT & _BODEN_OFF & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _CPD_OFF & _CP_OFF
ERRORLEVEL -302

cblock		20h
pwmcounter, channel1, channel2, period
endc

ORG		0000h
goto	setup

ORG		0004h
call	pwm
BCF	INTCON,2
RETFIE				;reset interrupt

setup
bsf	STATUS,RP0	;bank 1
movlw	0x3c
movwf	ANSEL
movlw	0x3c
movwf	TRISIO		;set I/O
movlw	0xd8
movwf	OPTION_REG	;set tmr0
bcf	STATUS,RP0
movlw	0x07		;turn off comparitors
movwf	CMCON
movlw	0xa0
movwf	INTCON		;set interrupt

start
movlw	0x09
movwf	ADCON0
goto	$+1 goto$+1
goto	$+1 goto$+1
goto	$+1 goto$+1
goto	$+1 goto$+1
goto	$+1 goto$+1
goto	$+1 goto$+1

bsf	ADCON0,1
btfsc	ADCON0,1
goto  $-1 movf ADRESH,0 movwf channel1 movlw 0x0d movwf ADCON0 goto$+1
goto	$+1 goto$+1
goto	$+1 goto$+1
goto	$+1 goto$+1
goto	$+1 goto$+1
goto	$+1 goto$+1
goto	$+1 bsf ADCON0,1 btfsc ADCON0,1 goto$-1
movf	ADRESH,0
movwf	channel2
goto	start

pwm
incf	period,1
btfss	STATUS,Z
goto	$+2 clrf period movf channel1,0 addwf period,0 btfss STATUS,C goto$+3
bsf	GPIO,0
goto	$+2 bcf GPIO,0 movf channel2,0 addwf period,0 btfss STATUS,C goto$+3
bsf	GPIO,1
return
bcf	GPIO,1
return

end

Last edited:
Status
Not open for further replies.

Loading