hardware PWM, set number of pulses

Discussion specific to the 24-pin ZX microcontrollers, e.g. ZX-24r, ZX-24s and ZX-24t.
Post Reply
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

hardware PWM, set number of pulses

Post by sturgessb »

Hi all

Playing around with steppers. Is it possible to define how many pulses I would like a hardware PWM channel to output, rather than just being able to specify a rate and duty cycle?

I basically want to say, send x number of pulses at a rate of x hz with high times of 40us.

I can do this using external PWM coprocessor, but would rather just be able to handle this project on the zx if possible.

Cheers

Ben
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: hardware PWM, set number of pulses

Post by dkinzer »

sturgessb wrote:Is it possible to define how many pulses I would like a hardware PWM channel to output [...]
The PWM functions of the ZBasic Library do not have the ability to output a specified number of pulses.

You could, however, implement the PWM directly and add an interrupt handler that counts the number of match interrupts, terminating the PWM when the desired number of pulses has been issued. See Tony's PWM application note AN-216 for the details on how to set up PWM.

Other alternatives would be to use OutputCapture() or to bit-bang the pulse stream while watching a timer to regulate the timing.
Last edited by dkinzer on 02 December 2013, 10:25 AM, edited 1 time in total.
- Don Kinzer
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

Thanks Don, The interrupt approach sounds workable, will give it a bash.
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

Sorry Don, don't answer if you are busy, but what would be the correct register settings to enable rising edge interrupts for PORTE_INT1 (pin 17)

And I'm guessing with the xmega i need to do something with the PMIC register too?
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

sturgessb wrote:[W]hat would be the correct register settings to enable rising edge interrupts for PORTE_INT1 (pin 17)
Unfortunately, you can't configure for rising edges only. You'll have to configure for both edges and then ignore the falling edge.

On the xmega, the ISC[2:0] bits of the PINxCTRL register of each port (where X is {0-7}) controls the edge/level configuration. The INTCTRL register of each port, in conjunction with the INTnMASK register, controls which pins can generate an interrupt.
- Don Kinzer
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

Thanks Don. Ill try and make sense of the docs this eve to work out what the register values should be.

I tried the timer route but the accuracy doesn't seem to be high enough to stop on exactly the right step.
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

It just occurred to me that one could use the "repeat count" of OutputCaptureEx() to generate a given number of pulses on any pin. In the example code below, the active/inactive time is hard-coded as 10uS and 90uS but one could pass parameters for that, too.

Code: Select all

Const pin as Byte = 14
Const pulseState as Byte = 1

Sub Main()
    ' initialize the pin to the "idle" state
    Call PutPin(pin, (Not pulseState) And 1)

    ' emit some pulses
    Call outputPulses(pin, pulseState, 5)
End Sub

'
'' outputPulses
'
' Output a number of pulses on a pin, assumed to be in the "idle" state.
'
Sub outputPulses(ByVal outPin as Byte, ByVal cnt as UnsignedInteger)
    ' initialize the OutputCapture() data for the desired pulse times
    Dim data(1 to 2) as UnsignedInteger
    data(1) = 147       ' about 10uS
    data(2) = 13271     ' about 90uS

    ' emit the pulses
    Call OutputCaptureEx(outPin, data, 2, (Not GetPin(outPin)) And 1, cnt)
End Sub
- Don Kinzer
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

Thanks again Don, that works, but I think I'm gonna try and push forwards with the interrupt method as it means I can modify the target step amount on the fly and stop when required. The output capture method would mean I could only fire and forget movement commands.

Looking at the docs now, will shout if I get stuck (most likely!)
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

So far I have

Code: Select all

Register.PORTE_INTCTRL = zx00000010
To select Int1, but I'm really not sure what the value for Register.PORTE_INT1MASK should be for E.1 pin

I thought it would just be zx00000001 to enable INT1, but that doesn't seem to work.

Sorry, but any pointers? Thanks
sturgessb
Posts: 287
Joined: 25 April 2008, 6:34 AM
Location: Norwich, UK

Post by sturgessb »

Ah, this is correct I think…

Code: Select all

Register.PORTE_PIN1CTRL = zx00000001
Register.PORTE_INTCTRL = zx00000110
Register.PORTE_INT1MASK = zx00000010
well, it seems to doing what i want anyway!
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

sturgessb wrote:Ah, this is correct I think…
Yes, that looks correct.
- Don Kinzer
Post Reply