Reply by engi...@gmail.com●October 24, 20132013-10-24
Bob,
Driving a servo should be easy and doesn't require any interrupts (unless
I don't fully understand your question). You have to do quite a bit of
setup in the timers to get it going, but once it's going the timer device
generates the waveform for you.
I'm using the free-version of the Keil dev environment. Just grab the
whole lpc1114fn28 folder, navigate to 'pwm' or 'pwmfan'
samples, open and build them. I've been working on BLDC control lately and
have been modifying the shared headers in core. So if it doesn't build
properly just send me a note and I'll fix it.
Cheers,
Chris
---In l..., wrote:
Using a match interrupt and diddling with stuff in the ISR will result in duty
cycle jitter.
Jeff
--- In l... mailto:l..., "bobryanmm" wrote:
>
> In this case that will work but in certain circumstances it wouldn't
because we'd have the high pulse at the end of the cycle. I went ahead and
disabled PWM on the outputs and use EMC0 to clear the EM0 bit on compare match
then trigger and interrupt on EM3 compare match and inside that interrupt
routine I'm setting EM0 high again.. This does work fine but I would prefer
doing this without use of interrupts or additional processing. After reading the
datasheet a number of times I don't think this is possible. Thanks -Bob
>
> --- In l... mailto:l..., "ksdoubleshooter" wrote:
> >
> > Handle the inversion is software. For example, if you want a two
millisecond inverted pulse, set up the PWM for 18 milliseconds.
> >
> > Jeff
> >
> > --- In l... mailto:l..., "bobryanmm" wrote:
> > >
> > > I am trying to drive a servo using the following function and I've
messed with the EMR register but I think the values are basically ignored
because I've got PWM output enabled for MR0/MR1. The datasheet says we need
to read a set of rules that apply when PWM mode is used. I know I can get around
this by triggering interrupts with the timers/compare modules then toggling the
IO pins in the interrupt functions but I'd be surprised if there
wasn't a simpler way to do this that might not require any processing.
Right now my waveform is inverted of a valid 50Hz servo pulse (1-2ms high then
18-19ms low). I've found some example code online but not for these
processors and the LPC17xx seems to have a different PWM peripheral (requires
manual latching of the data, makes use of other bits/registers not described in
the LPC1114 datasheet).
> > >
> > > void PWM_init(void)
> > > {
> > > LPC_TMR16B0->TCR = 0; //Disable Timer0
> > > LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);
> > > LPC_TMR16B0->EMR = (1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<10);
> > > LPC_TMR16B0->PR = 11; //set prescaler to 12 for ~20ms period
> > >
> > > LPC_IOCON->PIO0_8 &= ~0x07;
> > > LPC_IOCON->PIO0_9 &= ~0x07;
> > > LPC_IOCON->PIO0_8 |= 0x02;
> > > LPC_IOCON->PIO0_9 |= 0x02;
> > >
> > > LPC_TMR16B0->MR3 = 20000-1;
> > > LPC_TMR16B0->MR0 = 1500;
> > > LPC_TMR16B0->MR1 = 1500;
> > > LPC_TMR16B0->MCR = 0x400;
> > > LPC_TMR16B0->PWMC = 0x0B;
> > >
> > > NVIC_EnableIRQ(TIMER_16_0_IRQn); // Enable the TIMER1 Interrupt
> > > LPC_TMR16B0->TCR = 1; // Enable Timer16
> > > }
> > >
> > > Any help is quite welcome. Thanks -Bob
> > >
> >
>
Reply by ksdoubleshooter●August 21, 20132013-08-21
Using a match interrupt and diddling with stuff in the ISR will result in duty
cycle jitter.
Jeff
--- In l..., "bobryanmm" wrote: >
> In this case that will work but in certain circumstances it wouldn't
because we'd have the high pulse at the end of the cycle. I went ahead and
disabled PWM on the outputs and use EMC0 to clear the EM0 bit on compare match
then trigger and interrupt on EM3 compare match and inside that interrupt
routine I'm setting EM0 high again.. This does work fine but I would prefer
doing this without use of interrupts or additional processing. After reading the
datasheet a number of times I don't think this is possible. Thanks -Bob
>
> --- In l..., "ksdoubleshooter" wrote:
> >
> > Handle the inversion is software. For example, if you want a two millisecond
inverted pulse, set up the PWM for 18 milliseconds.
> >
> > Jeff
> >
> > --- In l..., "bobryanmm" wrote:
> > >
> > > I am trying to drive a servo using the following function and I've
messed with the EMR register but I think the values are basically ignored
because I've got PWM output enabled for MR0/MR1. The datasheet says we need
to read a set of rules that apply when PWM mode is used. I know I can get around
this by triggering interrupts with the timers/compare modules then toggling the
IO pins in the interrupt functions but I'd be surprised if there
wasn't a simpler way to do this that might not require any processing.
Right now my waveform is inverted of a valid 50Hz servo pulse (1-2ms high then
18-19ms low). I've found some example code online but not for these
processors and the LPC17xx seems to have a different PWM peripheral (requires
manual latching of the data, makes use of other bits/registers not described in
the LPC1114 datasheet).
> > >
> > > void PWM_init(void)
> > > {
> > > LPC_TMR16B0->TCR = 0; //Disable Timer0
> > > LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);
> > > LPC_TMR16B0->EMR = (1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<10);
> > > LPC_TMR16B0->PR = 11; //set prescaler to 12 for ~20ms period
> > >
> > > LPC_IOCON->PIO0_8 &= ~0x07;
> > > LPC_IOCON->PIO0_9 &= ~0x07;
> > > LPC_IOCON->PIO0_8 |= 0x02;
> > > LPC_IOCON->PIO0_9 |= 0x02;
> > >
> > > LPC_TMR16B0->MR3 = 20000-1;
> > > LPC_TMR16B0->MR0 = 1500;
> > > LPC_TMR16B0->MR1 = 1500;
> > > LPC_TMR16B0->MCR = 0x400;
> > > LPC_TMR16B0->PWMC = 0x0B;
> > >
> > > NVIC_EnableIRQ(TIMER_16_0_IRQn); // Enable the TIMER1 Interrupt
> > > LPC_TMR16B0->TCR = 1; // Enable Timer16
> > > }
> > >
> > > Any help is quite welcome. Thanks -Bob
> > >
>
Reply by ksdoubleshooter●August 21, 20132013-08-21
The PWM mode for the LPC1100 timers has some issues, the polarity is the
opposite of what most might expect and setting up a match register with the same
value as the terminal count cause a glitch on the output.
The following code will produce a exactly what you originally were trying to
accomplish -- polarity inversion and de-glitching by changing the pin to GPIO in
the case where a value of 0 is passed for the duty cycle.
void pwm_output(uint32_t chn, uint32_t duty_cycle)
{
switch (chn)
{
case 0:
if (duty_cycle == 0)
{
IOCON_PIO1_9 &= ~7; //mat0 back to io
GPIO1_MASKED_RW(1 << 9) = 0; //and set low
}
else
{
if (duty_cycle > 1000)
duty_cycle = 1000;
TMR16B1MR0 = 1000 - duty_cycle;
IOCON_PIO1_9 |= 1; //p1.9 set to t16b1 mat0
}
break;
case 1:
if (duty_cycle == 0)
{
IOCON_PIO1_10 &= ~7; //mat1 back to io
GPIO1_MASKED_RW(1 << 10) = 0; //and set low
}
else
{
if (duty_cycle > 1000)
duty_cycle = 1000;
TMR16B1MR1 = 1000 - duty_cycle;
IOCON_PIO1_10 |= 2; //p1.10 set to t16b1 mat1
}
break;
}
}
--- In l..., "bobryanmm" wrote: >
> In this case that will work but in certain circumstances it wouldn't
because we'd have the high pulse at the end of the cycle. I went ahead and
disabled PWM on the outputs and use EMC0 to clear the EM0 bit on compare match
then trigger and interrupt on EM3 compare match and inside that interrupt
routine I'm setting EM0 high again.. This does work fine but I would prefer
doing this without use of interrupts or additional processing. After reading the
datasheet a number of times I don't think this is possible. Thanks -Bob
>
> --- In l..., "ksdoubleshooter" wrote:
> >
> > Handle the inversion is software. For example, if you want a two millisecond
inverted pulse, set up the PWM for 18 milliseconds.
> >
> > Jeff
> >
> > --- In l..., "bobryanmm" wrote:
> > >
> > > I am trying to drive a servo using the following function and I've
messed with the EMR register but I think the values are basically ignored
because I've got PWM output enabled for MR0/MR1. The datasheet says we need
to read a set of rules that apply when PWM mode is used. I know I can get around
this by triggering interrupts with the timers/compare modules then toggling the
IO pins in the interrupt functions but I'd be surprised if there
wasn't a simpler way to do this that might not require any processing.
Right now my waveform is inverted of a valid 50Hz servo pulse (1-2ms high then
18-19ms low). I've found some example code online but not for these
processors and the LPC17xx seems to have a different PWM peripheral (requires
manual latching of the data, makes use of other bits/registers not described in
the LPC1114 datasheet).
> > >
> > > void PWM_init(void)
> > > {
> > > LPC_TMR16B0->TCR = 0; //Disable Timer0
> > > LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);
> > > LPC_TMR16B0->EMR = (1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<10);
> > > LPC_TMR16B0->PR = 11; //set prescaler to 12 for ~20ms period
> > >
> > > LPC_IOCON->PIO0_8 &= ~0x07;
> > > LPC_IOCON->PIO0_9 &= ~0x07;
> > > LPC_IOCON->PIO0_8 |= 0x02;
> > > LPC_IOCON->PIO0_9 |= 0x02;
> > >
> > > LPC_TMR16B0->MR3 = 20000-1;
> > > LPC_TMR16B0->MR0 = 1500;
> > > LPC_TMR16B0->MR1 = 1500;
> > > LPC_TMR16B0->MCR = 0x400;
> > > LPC_TMR16B0->PWMC = 0x0B;
> > >
> > > NVIC_EnableIRQ(TIMER_16_0_IRQn); // Enable the TIMER1 Interrupt
> > > LPC_TMR16B0->TCR = 1; // Enable Timer16
> > > }
> > >
> > > Any help is quite welcome. Thanks -Bob
> > >
>
Reply by rtstofer●August 20, 20132013-08-20
--- In l..., "bobryanmm" wrote: >
> In this case that will work but in certain circumstances it wouldn't
because we'd have the high pulse at the end of the cycle.
Cycles come and go but where they start is up to you. I maintain that the cycle
starts whenever the pulse goes high. I can look at the off time as being ahead
of the leading edge or after the trailing edge - my rules.
Richard
Reply by bobryanmm●August 20, 20132013-08-20
In this case that will work but in certain circumstances it wouldn't
because we'd have the high pulse at the end of the cycle. I went ahead and
disabled PWM on the outputs and use EMC0 to clear the EM0 bit on compare match
then trigger and interrupt on EM3 compare match and inside that interrupt
routine I'm setting EM0 high again.. This does work fine but I would prefer
doing this without use of interrupts or additional processing. After reading the
datasheet a number of times I don't think this is possible. Thanks -Bob
--- In l..., "ksdoubleshooter" wrote: >
> Handle the inversion is software. For example, if you want a two millisecond
inverted pulse, set up the PWM for 18 milliseconds.
>
> Jeff
>
> --- In l..., "bobryanmm" wrote:
> >
> > I am trying to drive a servo using the following function and I've
messed with the EMR register but I think the values are basically ignored
because I've got PWM output enabled for MR0/MR1. The datasheet says we need
to read a set of rules that apply when PWM mode is used. I know I can get around
this by triggering interrupts with the timers/compare modules then toggling the
IO pins in the interrupt functions but I'd be surprised if there
wasn't a simpler way to do this that might not require any processing.
Right now my waveform is inverted of a valid 50Hz servo pulse (1-2ms high then
18-19ms low). I've found some example code online but not for these
processors and the LPC17xx seems to have a different PWM peripheral (requires
manual latching of the data, makes use of other bits/registers not described in
the LPC1114 datasheet).
> >
> > void PWM_init(void)
> > {
> > LPC_TMR16B0->TCR = 0; //Disable Timer0
> > LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);
> > LPC_TMR16B0->EMR = (1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<10);
> > LPC_TMR16B0->PR = 11; //set prescaler to 12 for ~20ms period
> >
> > LPC_IOCON->PIO0_8 &= ~0x07;
> > LPC_IOCON->PIO0_9 &= ~0x07;
> > LPC_IOCON->PIO0_8 |= 0x02;
> > LPC_IOCON->PIO0_9 |= 0x02;
> >
> > LPC_TMR16B0->MR3 = 20000-1;
> > LPC_TMR16B0->MR0 = 1500;
> > LPC_TMR16B0->MR1 = 1500;
> > LPC_TMR16B0->MCR = 0x400;
> > LPC_TMR16B0->PWMC = 0x0B;
> >
> > NVIC_EnableIRQ(TIMER_16_0_IRQn); // Enable the TIMER1 Interrupt
> > LPC_TMR16B0->TCR = 1; // Enable Timer16
> > }
> >
> > Any help is quite welcome. Thanks -Bob
>
Reply by ksdoubleshooter●August 19, 20132013-08-19
Handle the inversion is software. For example, if you want a two millisecond
inverted pulse, set up the PWM for 18 milliseconds.
Jeff
--- In l..., "bobryanmm" wrote: >
> I am trying to drive a servo using the following function and I've messed
with the EMR register but I think the values are basically ignored because
I've got PWM output enabled for MR0/MR1. The datasheet says we need to read
a set of rules that apply when PWM mode is used. I know I can get around this by
triggering interrupts with the timers/compare modules then toggling the IO pins
in the interrupt functions but I'd be surprised if there wasn't a
simpler way to do this that might not require any processing. Right now my
waveform is inverted of a valid 50Hz servo pulse (1-2ms high then 18-19ms low).
I've found some example code online but not for these processors and the
LPC17xx seems to have a different PWM peripheral (requires manual latching of
the data, makes use of other bits/registers not described in the LPC1114
datasheet).
>
> void PWM_init(void)
> {
> LPC_TMR16B0->TCR = 0; //Disable Timer0
> LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);
> LPC_TMR16B0->EMR = (1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<10);
> LPC_TMR16B0->PR = 11; //set prescaler to 12 for ~20ms period
>
> LPC_IOCON->PIO0_8 &= ~0x07;
> LPC_IOCON->PIO0_9 &= ~0x07;
> LPC_IOCON->PIO0_8 |= 0x02;
> LPC_IOCON->PIO0_9 |= 0x02;
>
> LPC_TMR16B0->MR3 = 20000-1;
> LPC_TMR16B0->MR0 = 1500;
> LPC_TMR16B0->MR1 = 1500;
> LPC_TMR16B0->MCR = 0x400;
> LPC_TMR16B0->PWMC = 0x0B;
>
> NVIC_EnableIRQ(TIMER_16_0_IRQn); // Enable the TIMER1 Interrupt
> LPC_TMR16B0->TCR = 1; // Enable Timer16
> }
>
> Any help is quite welcome. Thanks -Bob
>
Reply by bobryanmm●August 17, 20132013-08-17
Mauro,
Thanks for the response. I am definitely not inverting the signal in hardware.
The duty cycle is as expected though the signal is inverted so the actual duty
cycle is 100%-desired% (in my case a 80-90%). The EMR register seems to dictate
if the EM0 output should be set or cleared on compare match but there is a note
that if PWM is enabled in the PWMC register that EMCn has no affect.
"If the match outputs are configured as PWM output in the PWMCON registers
(Section 18.7.12), the function of the external match registers is determined by
the PWM rules (Section 18.7.13 "Rules for single edge controlled PWM outputs" on
page 340)."
If we look up the rules on page 340 we get:
"
18.7.13 Rules for single edge controlled PWM outputs
1. All single edge controlled PWM outputs go LOW at the beginning of each PWM
cycle (timer is set to zero) unless their match value is equal to zero.
2. Each PWM output will go HIGH when its match value is reached. If no match
occurs (i.e. the match value is greater than the PWM cycle length), the PWM
output remains continuously LOW.
3. If a match value larger than the PWM cycle length is written to the match
register, and the PWM signal is HIGH already, then the PWM signal will be
cleared on the next start of the next PWM cycle.
4. If a match register contains the same value as the timer reset value (the PWM
cycle length), then the PWM output will be reset to LOW on the next clock tick.
Therefore, the PWM output will always consist of a one clock tick wide positive
pulse with a period determined by the PWM cycle length (i.e. the timer reload
value).
5. If a match register is set to zero, then the PWM output will go to HIGH the
first time the timer goes back to zero and will stay HIGH continuously.
Note: When the match outputs are selected to serve as PWM outputs, the timer
reset (MRnR) and timer stop (MRnS) bits in the Match Control Register MCR must
be set to 0 except for the match register setting the PWM cycle length. For this
register, set the MRnR bit to 1 to enable the timer reset when the timer value
matches the value of the corresponding match register.
"
To me this is pretty clear that rules 1 and 2 say the output will be set low
upon timer reset and set high on compare match. I've worked with lots of
micros that allow these outputs to be inverted rather simply but that
doesn't seem to be the case with this chip. I know there are ways to work
around it but I'm just wondering if anyone might have insight on this
limitation or if I'm misreading the datasheet etc.
Thanks again -Bob
--- In l..., Mauro Lenz wrote: >
> Hi Bob,
>
> are your PWM signal working fine when you set a another duty-cycle? If
> yes you probably are inverting your signal on your hardware (probably on
> signal isolation using a opto or using a transistor). You can change
> this two ways:
> - Adding a transistor on your hardware to invert your driver signal;
> - invert you signal on software. To invert in software, the easier way
> is taking your full duty-cycle (100%) value and subtract your calculated
> duty cycle (for example: for 2ms high and 18ms low you are using a 10%
> duty cycle and to invert the waveform you need to use 90% of duty cycle).
> I use LPC2136/38 to control servo motors using PWM and build my own
> driver for it (low power), using hardware invertion.
>
> Atenciosamente,
>
> Mauro L. Lenz
> Fone: (55) 8115-6944
> Skype: mauro_eafs
>
> "Ajude a combater o Spam. Ao encaminhar uma mensagem, apague o e-mail do
remetente e utilize o campo CCo quando enviar para mais de um destinatio."
>
> Em 17/08/2013 12:20, bobryanmm escreveu:
> > void PWM_init(void)
>
Reply by Mauro Lenz●August 17, 20132013-08-17
Hi Bob,
are your PWM signal working fine when you set a another duty-cycle? If
yes you probably are inverting your signal on your hardware (probably on
signal isolation using a opto or using a transistor). You can change
this two ways:
- Adding a transistor on your hardware to invert your driver signal;
- invert you signal on software. To invert in software, the easier way
is taking your full duty-cycle (100%) value and subtract your calculated
duty cycle (for example: for 2ms high and 18ms low you are using a 10%
duty cycle and to invert the waveform you need to use 90% of duty cycle).
I use LPC2136/38 to control servo motors using PWM and build my own
driver for it (low power), using hardware invertion.
Atenciosamente,
Mauro L. Lenz
Fone: (55) 8115-6944
Skype: mauro_eafs
"Ajude a combater o Spam. Ao encaminhar uma mensagem, apague o e-mail do
remetente e utilize o campo CCo quando enviar para mais de um destinatio."
Em 17/08/2013 12:20, bobryanmm escreveu: > void PWM_init(void)
Reply by bobryanmm●August 17, 20132013-08-17
I am trying to drive a servo using the following function and I've messed
with the EMR register but I think the values are basically ignored because
I've got PWM output enabled for MR0/MR1. The datasheet says we need to read
a set of rules that apply when PWM mode is used. I know I can get around this by
triggering interrupts with the timers/compare modules then toggling the IO pins
in the interrupt functions but I'd be surprised if there wasn't a
simpler way to do this that might not require any processing. Right now my
waveform is inverted of a valid 50Hz servo pulse (1-2ms high then 18-19ms low).
I've found some example code online but not for these processors and the
LPC17xx seems to have a different PWM peripheral (requires manual latching of
the data, makes use of other bits/registers not described in the LPC1114
datasheet).
void PWM_init(void)
{
LPC_TMR16B0->TCR = 0; //Disable Timer0
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);
LPC_TMR16B0->EMR = (1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<10);
LPC_TMR16B0->PR = 11; //set prescaler to 12 for ~20ms period