|
|
View previous topic :: View next topic |
Author |
Message |
randy.shaffer
Joined: 21 Mar 2018 Posts: 51
|
Need help with PWM on 16F15323 |
Posted: Fri Sep 14, 2018 1:16 pm |
|
|
Code: | #include <16F15323.h>
#device ADC = 10
#device ICD = TRUE
#use delay(clock = 32MHZ, internal)
#use rs232(baud = 57600, parity = N, xmit = PIN_C4, rcv = PIN_C5, \
bits = 8, stream = PORT1)
#PIN_SELECT CCP1OUT = PIN_A2
#include <stdio.h>
/* Function Prototypes */
void TIMER0_ISR(); // Timer 0 interrupt service routine
unsigned int16 get_ADC_channel(int8 ADC_channel);
/* Global Variables */
unsigned int16 T0_COUNT = 0;
void main()
{
float VR = 5.0, VIN;
unsigned int16 PWM_duty;
unsigned int16 INDUCTOR_CURRENT = 0; // analog of inductor current
unsigned int16 INPUT_VOLTAGE = 0; // analog of input voltage
unsigned int16 OUTPUT_VOLTAGE = 0; // analog of output voltage
unsigned int16 VOUT = 0, IL = 0;
output_bit(PIN_A2, 0); // turn off high-side MOSFET
set_tris_a(0x20); // set A5 as input, A2 as output
set_tris_c(0x03); // set C0, C1 as inputs; C3 as output
setup_oscillator(OSC_HFINTRC_32MHZ); // Fosc = 32 MHz
setup_vref(VREF_ON|VREF_ADC_4v096); // Set Vref = 4.096 V for ADC
setup_adc(ADC_CLOCK_DIV_32); // ADC clock is 32/32 = 1 MHz
setup_adc_ports(sAN5|sAN16|sAN17, VSS_FVR); // A5, C0, & C1 are analog inputs
set_timer0(0xFD8E); // Initialize Timer 0 for 10 ms
setup_timer_0(T0_INTERNAL | T0_DIV_128); // clocked @15.625 kHz (Fosc/(4*128))
enable_interrupts(INT_TIMER0); // enable Timer 0 interrupts
enable_interrupts(global); // enable all interrupts
setup_CCP1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1, 100, 1);
PWM_duty = 50;
set_PWM1_duty(PWM_duty);
while(TRUE)
{
.
.
.
}
|
I can get the PWM to work with the #use pwm directive but waveform jitter increases with frequency. Not getting anything out of A2 with the above code.
Last edited by randy.shaffer on Fri Sep 14, 2018 1:46 pm; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Fri Sep 14, 2018 1:43 pm |
|
|
Some comments:
1) Use the code buttons!.... Makes the code much easier to read.
2) Your PR2 value (timer2), probably wants to be 99. Remember to give /100, you have to use 99.
3) The duty you are giving will only be 12.5% duty cycle. For 50% you would want 200. So a very small pulse. 79KHz, and a pulse width of 1.6uSec.
4) The chip will wake by default with the slew rate limit enabled on the pins. Now at your frequency, it is possible that with the slew rate limit enabled, the output would be very attenuated. Might be a problem. With the pulse width at only 1.6uSec, this could easily hardly show at all...
5) General comment, if a pin doesn't give what you expect, make sure yoiu turn off the other peripherals on the pin. ZCD etc.
6) A2 should not be set as output, till _after_ the CCP is configured. The data sheet is quite specific that it should be set as input while you configure the peripheral.
7) What compiler version?. We need to know. |
|
|
randy.shaffer
Joined: 21 Mar 2018 Posts: 51
|
|
Posted: Fri Sep 14, 2018 1:58 pm |
|
|
Code: | #include <16F15323.h>
#device ADC = 10
#device ICD = TRUE
#use delay(clock = 32MHZ, internal)
#use rs232(baud = 57600, parity = N, xmit = PIN_C4, rcv = PIN_C5, \
bits = 8, stream = PORT1)
#PIN_SELECT CCP1OUT = PIN_A2
//#use pwm(PWM1, TIMER = 2, FREQUENCY = 100kHz, PWM_OFF, STREAM = PWM_OUT)
#include <stdio.h>
/* Function Prototypes */
void TIMER0_ISR(); // Timer 0 interrupt service routine
unsigned int16 get_ADC_channel(int8 ADC_channel);
/* Global Variables */
unsigned int16 T0_COUNT = 0;
void main()
{
float VR = 5.0, VIN;
unsigned int16 PWM_duty;
unsigned int16 INDUCTOR_CURRENT = 0; // analog of inductor current
unsigned int16 INPUT_VOLTAGE = 0; // analog of input voltage
unsigned int16 OUTPUT_VOLTAGE = 0; // analog of output voltage
unsigned int16 VOUT = 0, IL = 0;
output_bit(PIN_A2, 0); // turn off high-side MOSFET
setup_oscillator(OSC_HFINTRC_32MHZ); // Fosc = 32 MHz
setup_vref(VREF_ON|VREF_ADC_4v096); // Set Vref = 4.096 V for ADC
setup_adc(ADC_CLOCK_DIV_32); // ADC clock is 32/32 = 1 MHz
setup_adc_ports(sAN5|sAN16|sAN17, VSS_FVR); // A5, C0, & C1 are analog inputs
set_timer0(0xFD8E); // Initialize Timer 0 for 10 ms
setup_timer_0(T0_INTERNAL | T0_DIV_128); // clocked @15.625 kHz (Fosc/(4*128))
enable_interrupts(INT_TIMER0); // enable Timer 0 interrupts
enable_interrupts(global); // enable all interrupts
setup_CCP1(CCP_PWM);
set_tris_a(0x20); // set A5 as input, A2 as output
set_tris_c(0x03); // set C0, C1 as inputs; C3 as output
setup_timer_2(T2_DIV_BY_1, 99, 1);
PWM_duty = 200;
set_PWM1_duty(PWM_duty);
while(TRUE)
{
.
.
.
}
|
Thank you. I am using the CCS C compiler v5.080. How do you disable the slew rate limit? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Fri Sep 14, 2018 2:26 pm |
|
|
Have a look at this thread:
<http://www.ccsinfo.com/forum/viewtopic.php?t=57171&highlight=slew+rate> |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 14, 2018 2:27 pm |
|
|
Currently you have a soft UART. To make it use the hardware UART, you
need to add the two lines shown in bold below, above your #use rs232()
statement:
Quote: | #pin_select U1TX=PIN_C4
#pin_select U1RX=PIN_C5
#use rs232(baud = 57600, parity = N, xmit = PIN_C4, rcv = PIN_C5, \
bits = 8, stream = PORT1) |
You can tell this by looking at the .LST file before and after making the
changes above. |
|
|
randy.shaffer
Joined: 21 Mar 2018 Posts: 51
|
|
Posted: Fri Sep 14, 2018 2:47 pm |
|
|
Code: | #include <16F15323.h>
#device ADC = 10
#device ICD = TRUE
#use delay(clock = 32MHZ, internal)
#pin_select U1TX = PIN_C4
#pin_select U1RX = PIN_C5
#use rs232(baud = 57600, parity = N, xmit = PIN_C4, rcv = PIN_C5, \
bits = 8, stream = PORT1)
#PIN_SELECT CCP1OUT = PIN_A2
//#use pwm(PWM1, TIMER = 2, FREQUENCY = 100kHz, PWM_OFF, STREAM = PWM_OUT)
#include <stdio.h>
/* Function Prototypes */
void TIMER0_ISR(); // Timer 0 interrupt service routine
unsigned int16 get_ADC_channel(int8 ADC_channel);
/* Global Variables */
unsigned int16 T0_COUNT = 0;
void main()
{
float VR = 5.0, VIN;
unsigned int16 PWM_duty;
unsigned int16 INDUCTOR_CURRENT = 0; // analog of inductor current
unsigned int16 INPUT_VOLTAGE = 0; // analog of input voltage
unsigned int16 OUTPUT_VOLTAGE = 0; // analog of output voltage
unsigned int16 VOUT = 0, IL = 0;
output_bit(PIN_A2, 0); // turn off high-side MOSFET
setup_oscillator(OSC_HFINTRC_32MHZ); // Fosc = 32 MHz
setup_vref(VREF_ON|VREF_ADC_4v096); // Set Vref = 4.096 V for ADC
setup_adc(ADC_CLOCK_DIV_32); // ADC clock is 32/32 = 1 MHz
setup_adc_ports(sAN5|sAN16|sAN17, VSS_FVR); // A5, C0, & C1 are analog inputs
set_timer0(0xFD8E); // Initialize Timer 0 for 10 ms
setup_timer_0(T0_INTERNAL | T0_DIV_128); // clocked @15.625 kHz (Fosc/(4*128))
enable_interrupts(INT_TIMER0); // enable Timer 0 interrupts
enable_interrupts(global); // enable all interrupts
setup_CCP1(CCP_PWM);
set_tris_a(0x20); // set A5 as input, A2 as output
set_tris_c(0x03); // set C0, C1 as inputs; C3 as output
setup_timer_2(T2_DIV_BY_1, 99, 1);
PWM_duty = 200;
set_PWM1_duty(PWM_duty);
while(TRUE)
{ ...
|
Thank you again. Sorry but I did not see anything related to disabling the slew rate limit in that thread. Still no output on A2 with the above code.
Any ideas as to why the PWM waveform has jitter that increases with frequency with the #use pwm directive? At 80 kHz it is really, really bad. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 14, 2018 3:35 pm |
|
|
randy.shaffer wrote: |
Sorry but I did not see anything related to disabling the slew rate limit in
that thread. Still no output on A2 with the above code.
|
See page 2 of the thread. Note the section on the SLRCON registers.
http://www.ccsinfo.com/forum/viewtopic.php?t=57171&start=15 |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Fri Sep 14, 2018 3:39 pm |
|
|
randy.shaffer wrote: |
Thank you again. Sorry but I did not see anything related to disabling the slew rate limit in that thread. Still no output on A2 with the above code.
Any ideas as to why the PWM waveform has jitter that increases with frequency with the #use pwm directive? At 80 kHz it is really, really bad. |
Look at chapter 14 of the data sheet for your PIC, page 172. SLRCONx registers. They default to 1 (on). If on, any really fast events you try to generate will not appear as you expect. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Fri Sep 14, 2018 11:30 pm |
|
|
Seriously, on page 2 of the thread, I post:
Quote: |
Suggestion.
Clear the SLRCON registers. SLRCONA, SLRCONB & SLRCONC. Do something like:
Code:
#byte SLRCONA=getenv("SFR:SLRCONA")
#byte SLRCONB=getenv("SFR:SLRCONB")
#byte SLRCONC=getenv("SFR:SLRCONC")
//Then in your main
SLRCONA=SLRCONB=SLRCONC=0;
These all default to '1' which implies slew rate limiting is enabled. Though the limitation should still allow the clock rates involved, it's worth trying with this off....
|
It turned out to fix the problem in this thread, where the poster was trying to output the CLKOUT, but was finding that it didn't work at anything faster than quite slow rates (it appeared that in this case the slew rate limit was actually slower than the data sheet figure...). |
|
|
randy.shaffer
Joined: 21 Mar 2018 Posts: 51
|
|
Posted: Mon Sep 17, 2018 9:04 am |
|
|
Code: | #include <16F15323.h>
#device ADC = 10
#device ICD = TRUE
#use delay(clock = 32MHZ, internal)
#pin_select U1TX = PIN_C4
#pin_select U1RX = PIN_C5
#use rs232(baud = 57600, parity = N, xmit = PIN_C4, rcv = PIN_C5, \
bits = 8, stream = PORT1)
#PIN_SELECT CCP1OUT = PIN_A2
#byte SLRCONA = getenv("SFR:SLRCONA")
#include <stdio.h>
/* Function Prototypes */
void TIMER0_ISR(); // Timer 0 interrupt service routine
unsigned int16 get_ADC_channel(int8 ADC_channel);
/* Global Variables */
unsigned int16 T0_COUNT = 0;
void main()
{
SLRCONA = 0;
float VR = 5.0, VIN;
unsigned int16 PWM_duty;
unsigned int16 INDUCTOR_CURRENT = 0; // analog of inductor current
unsigned int16 INPUT_VOLTAGE = 0; // analog of input voltage
unsigned int16 OUTPUT_VOLTAGE = 0; // analog of output voltage
unsigned int16 VOUT = 0, IL = 0;
output_bit(PIN_A2, 0); // turn off high-side MOSFET
setup_oscillator(OSC_HFINTRC_32MHZ); // Fosc = 32 MHz
setup_vref(VREF_ON|VREF_ADC_4v096); // Set Vref = 4.096 V for ADC
setup_adc(ADC_CLOCK_DIV_32); // ADC clock is 32/32 = 1 MHz
setup_adc_ports(sAN5|sAN16|sAN17, VSS_FVR); // A5, C0, & C1 are analog inputs
set_timer0(0xFD8E); // Initialize Timer 0 for 10 ms
setup_timer_0(T0_INTERNAL | T0_DIV_128); // clocked @15.625 kHz (Fosc/(4*128))
enable_interrupts(INT_TIMER0); // enable Timer 0 interrupts
enable_interrupts(global); // enable all interrupts
setup_CCP1(CCP_PWM);
set_tris_a(0x20); // set A5 as input, A2 as output
set_tris_c(0x03); // set C0, C1 as inputs; C3 as output
setup_timer_2(T2_DIV_BY_1, 99, 1);
PWM_duty = 200;
set_PWM1_duty(PWM_duty);
while(TRUE)
{...
|
Sorry about missing Page 2 of that post and thank you everyone for your help and suggestions. Still no output on A2 with the above code. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Mon Sep 17, 2018 3:24 pm |
|
|
OK...
a silly question but...
Can you code a simple 'toggle program' and turn an LED on/off on A2 ? If not maybe there's a solder bridge grounding that pin ?
Also I see you have ICD = TRUE. Does that option 'hijack' the A2 pin for any reason ? I never use an ICD so don't know...just thought it might be posssible.
Jay |
|
|
randy.shaffer
Joined: 21 Mar 2018 Posts: 51
|
|
Posted: Mon Sep 17, 2018 3:30 pm |
|
|
Hi Jay, I can get the PWM to work out of A2 if I use the #use pwm directive. But, the waveform has a terrible amount of jitter at the higher frequencies. It looks OK up to about 10 kHz but I want to operate at 80 - 100 kHz. I've had problems in the past with #use pwm causing some limitations and was trying a different approach without it. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Mon Sep 17, 2018 6:00 pm |
|
|
OK, so it's not a basic hardware issue, rather some 'PWM setup code', sigh. I'm on my bkp xp machine cause the W7 one went 'for a walk'.....
I'd cut 2 programs, one for say 8KHz and another for 16KHz. 8 should work, 16 not so good. If so, dump the listings and check the code. Play PIC and confirm the correct registers are set properly.
Wish I could help more but all the recent CCS stuff is on, yeah the dead W7 PC.
Jay |
|
|
randy.shaffer
Joined: 21 Mar 2018 Posts: 51
|
|
Posted: Wed Sep 19, 2018 11:54 am |
|
|
Code: | #include <16F15323.h>
#PIN_SELECT CCP1OUT = PIN_A2
void main()
{
setup_oscillator(OSC_HFINTRC_32MHZ);
Setup_CCP1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1 | T2_CLK_INTERNAL, 79, 1);
set_tris_a(0xFB); // set A2 as output
set_PWM1_duty(160);
while(TRUE)
{
// ...
}
} |
Thank you, Jay. I got it to work but, sadly, the waveform still has terrible jitter. ORing T2_CLK_INTERNAL with T2_DIV_BY_1 made it work.
If anyone knows why the PWM signal has the jitters and how to fix it, I would greatly appreciate the insight. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Sep 19, 2018 12:24 pm |
|
|
Can you measure the jitter on your oscilloscope ? How much is it ?
Also, you're enabling Timer0 interrupts but I don't see any Timer0
interrupt routine. Is that your entire program or did you not post all of it ?
Last edited by PCM programmer on Wed Sep 19, 2018 12:50 pm; edited 1 time in total |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|