Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Need two PWMs from PIC16F18856 microcontroller

Status
Not open for further replies.
Huh? A 'fixed PWM OF 30 % duty at 500 Hz' is not PWM. That's a pulse train. Of course this is possible. And, you do realize that this uP has a built-in PWM, right?
 
  • Like
Reactions: treez

    T

    Points: 2
    Helpful Answer Positive Rating
PWM Modulator Using Op-Amp (MAX492). The content is very simple, very helpful. Components in this article can help you understand better understanding of this article. For example, in this article, you can go to find and buy these components: MAX492.
 

Depending on the processor clock, it may be not possible to generate the intended low PWM frequencies directly with 8-bit PIC. It should be always possible with some software support.
 
I agree with FvM. Software PWM should be no problem, but direct PWM to those two pins may or may not be practical. You have picked a modern PIC, so the chances are higher.

If I get time, I will write some code for the job.
 

Not having much luck so far :(

Seems to be a tougher task than I imagined. Code Configurator tool (MCC) seems to suggest that PWM6 and PWM7 can output what you want to ports A1 and A2, but I have not succeeded in making it work. Might need someone cleverer than me to work it all out.
 

I now discover that PWM6 and PWM7 share the same timer- timer 2. This means that independent frequencies are not achievable in any obvious way.

Here is my best attempt so far. Uses mikroElectronika mikroC compiler to make PPS simpler, but if I ever manage a working version, porting to MPLABX should be straight forward. I test on PIC18857 as I have one, but I assume '56' and '57' are identical other than memory size.

Code:
// PWM test for PIC18857 using 4MHz internal oscillator
// amateur code - use at your own risk - author accepts no responsibility for anything, anywhere, ever
// Example of using NCO module for DDS  - gives approx 500Hz square wave on RA2

// spec from forum - We need to set a fixed PWM of 30% duty at approx. 500Hz on RA2.
// We also need a variable PWM on RA1. (frequency anywhere between 2kHz and 300Hz, but again it will be a fixed frequency)

void main() {

    OSCEN = 0x20;                                                               // internal oscillator explicit selection
    OSCFRQ = 0x02;                                                              // change internal oscillator to 4 MHz
    OSCCON1 = 0x60;                                                             // select internal oscillator, divider = 1

    ANSELA = 0;                                                                 // all digital
    TRISA = 0;                                                                  // all output
    LATA = 0;                                                                   // start all low
    ANSELB = 0;                                                                 // all digital
    TRISB = 0;                                                                  // all output
    LATB = 0;                                                                   // start all low
    ANSELC = 0;                                                                 // all digital
    TRISC = 0;                                                                  // all output
    LATC = 0;                                                                   // start all low

    Unlock_IOLOCK();                                                            // allow PPS mapping
    PPS_Mapping_NoLock(2, _OUTPUT, _PWM7OUT);                                   // Set pin A2 to be Output, and map PWM7 to it
    PPS_Mapping_NoLock(1, _OUTPUT, _NCO);                                       // Set pin A1 to be Output, and map NCO to it

    NCO1CON = 0x80;                                                             // enable NCO in 50% mode
    NCO1CLK = 0x00;                                                             // processor clock as NCO source
    NCO1INCH = 0x01;                                                            // always write high before low
    NCO1INCL = 0x03;                                                            // latch high and low together  - 0002 gives approx 1Hz

    T2CLKCON = 0x01;                                                            // Fosc/4 as clock
    T2CON = 0xd0;                                                               // T2 on, 1:4 prescaler, 1:1 postscaler
    T2HLT = 0x00;                                                               // free running mode
    
    PR2 = 0x3e;                                                                 // 0x3e seems to give 500Hz
    
    PWM7CON = 0x80;                                                             // enable PWM7
    PWM7DCH = 0x13;                                                             // 0x1300 seems to give 30% duty
    PWM7DCL = 0x00;                                                             // only top 2 bits used for fine control
    
    while(1){

    }
}
 

As far as I understand, timer 4 and 6 can be chosen alternatively for each PWM unit. But as mentioned before, you face the problem of maximal PWM period, you'll probably need to go for a more complex solution.
 

Hi,

500Hz, 30% duty cycle:

run an ISR about every 200us (5kHz):
* increment counter (0..9)
* on counter = 0, 1, 2 --> output HIGH, else output LOW.

But I don´t know if its possible with PIC to run an ISR every 200us...

Klaus
 

As far as I understand, timer 4 and 6 can be chosen alternatively for each PWM unit. But as mentioned before, you face the problem of maximal PWM period, you'll probably need to go for a more complex solution.
Amazing how I could miss the obvious! That's the solution, thanks FvM.

This mikroC code seems to work just fine, as far as I can tell:
Code:
// PWM test for PIC18857 using 4MHz internal oscillator
// amateur code - use at your own risk - author accepts no responsibility for anything, anywhere, ever

// spec from forum - We need to set a fixed PWM of 30% duty at approx. 500Hz on RA2.
// We also need a variable PWM on RA1. (frequency anywhere between 2kHz and 300Hz, but again it will be a fixed frequency)

void main() {

    OSCEN = 0x20;                                                               // internal oscillator explicit selection
    OSCFRQ = 0x02;                                                              // change internal oscillator to 4 MHz
    OSCCON1 = 0x60;                                                             // select internal oscillator, divider = 1

    ANSELA = 0;                                                                 // all digital
    TRISA = 0;                                                                  // all output
    LATA = 0;                                                                   // start all low
   
    Unlock_IOLOCK();                                                            // allow PPS mapping
    PPS_Mapping_NoLock(2, _OUTPUT, _PWM7OUT);                                   // Set pin A2 to be Output, and map PWM7 to it
    PPS_Mapping_NoLock(1, _OUTPUT, _PWM6OUT);                                   // Set pin A1 to be Output, and map PWM6 to it

    T2CLKCON = 0x01;                                                            // Fosc/4 as clock
    T2CON = 0xd0;                                                               // T2 on, 1:4 prescaler, 1:1 postscaler
    T2HLT = 0x00;                                                               // free running mode

    T6CLKCON = 0x01;                                                            // Fosc/4 as clock
    T6CON = 0xd0;                                                               // T6 on, 1:4 prescaler, 1:1 postscaler
    T6HLT = 0x00;                                                               // free running mode

    PR2 = 0x3e;                                                                 // 0x3e seems to give 500Hz
    PR6 = 0x4e;                                                                 // 0x4e seems to give 400Hz
    CCPTMRS1 = 0x1D;                                                            // PWM6 clocked by timer 6, PWM7 clocked by timer 2
    
    PWM6CON = 0x80;                                                             // enable PWM6
    PWM6DCH = 0x23;                                                             // 0x2300 seems to give 45% duty
    PWM6DCL = 0x00;                                                             // only top 2 bits used for fine control

    PWM7CON = 0x80;                                                             // enable PWM7
    PWM7DCH = 0x13;                                                             // 0x1300 seems to give 30% duty
    PWM7DCL = 0x00;                                                             // only top 2 bits used for fine control
    
    while(1);                                                                   // infinite loop
}
Will probably get around to porting this to MPLABX and XC8 sometime.... don't know when.

- - - Updated - - -

It took a lot less time than I expected to port code to XC8....

Code:
// PIC16F18856
// XC8 compiler
// MPLAB X V3.61
// date 10 Nov 2018

// updated by amateur coder who accepts no responsibility for anything, anywhere, ever
// spec from forum - We need to set a fixed PWM of 30% duty at approx. 500Hz on RA2.
// We also need a variable PWM on RA1. (frequency anywhere between 2kHz and 300Hz, but again it will be a fixed frequency)

// CONFIG1
#pragma config FEXTOSC = OFF                // External Oscillator mode selection bits (Oscillator not enabled)
#pragma config RSTOSC = HFINT1              // Power-up default value for COSC bits (HFINTOSC (1MHz))
#pragma config CLKOUTEN = OFF               // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2)
#pragma config CSWEN = ON                   // Clock Switch Enable bit (The NOSC and NDIV bits can be changed by user software)
#pragma config FCMEN = OFF                  // Fail-Safe Clock Monitor Enable bit (FSCM timer disabled)

// CONFIG2
#pragma config MCLRE = OFF                  // Master Clear Enable bit (MCLR pin function is port defined function)
#pragma config PWRTE = ON                   // Power-up Timer Enable bit (PWRT enabled)
#pragma config LPBOREN = OFF                // Low-Power BOR enable bit (ULPBOR disabled)
#pragma config BOREN = ON                   // Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)
#pragma config BORV = LO                    // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
#pragma config ZCD = OFF                    // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
#pragma config PPS1WAY = OFF                // Peripheral Pin Select one-way control (The PPSLOCK bit can be set and cleared repeatedly by software)
#pragma config STVREN = OFF                 // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will not cause a reset)

// CONFIG3
#pragma config WDTCPS = WDTCPS_31           // WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = OFF                   // WDT operating mode (WDT Disabled, SWDTEN is ignored)
#pragma config WDTCWS = WDTCWS_7            // WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC                  // WDT input clock selector (Software Control)

// CONFIG4
#pragma config WRT = OFF                    // UserNVM self-write protection bits (Write protection off)
#pragma config SCANE = not_available        // Scanner Enable bit (Scanner module is not available for use)
#pragma config LVP = OFF                    // Low Voltage Programming Enable bit (High Voltage on MCLR/Vpp must be used for programming)

// CONFIG5
#pragma config CP = OFF                     // UserNVM Program memory code protection bit (Program Memory code protection disabled)
#pragma config CPD = OFF                    // DataNVM code protection bit (Data EEPROM code protection disabled)

// #pragma config statements should precede project file includes.

#include <xc.h>                             // forum will remove xc.h within braces :(
#include <stdint.h>                         // forum will remove stdint.h within braces :(

#define  _XTAL_FREQ 4000000

void main(void){
    
    OSCEN = 0x20;                           // internal oscillator explicit selection
    OSCFRQ = 0x02;                          // change internal oscillator to 4 MHz
    OSCCON1 = 0x60;                         // select internal oscillator, divider = 1
    
    TRISA = 0x90;                           // RA4 temperature input, RA7 ?
    ANSELA = 0x10;                          // RA4 analogue selection for temperature input

    CM1CON0 = 0x00;
    CM1CON1 = 0x00;
    CM2CON0 = 0x00;
    CM2CON1 = 0x00;

    ZCDCON = 0x00;

    RA1PPS = 0x0e;                                                              // map PWM6 to RA1
    RA2PPS = 0x0f;                                                              // map PWM7 to RA1
    
    T2CLKCON = 0x01;                                                            // Fosc/4 as clock
    T2CON = 0xd0;                                                               // T2 on, 1:4 prescaler, 1:1 postscaler
    T2HLT = 0x00;                                                               // free running mode

    T6CLKCON = 0x01;                                                            // Fosc/4 as clock
    T6CON = 0xd0;                                                               // T6 on, 1:4 prescaler, 1:1 postscaler
    T6HLT = 0x00;                                                               // free running mode

    PR2 = 0x3e;                                                                 // 0x3e seems to give 500Hz
    PR6 = 0x4e;                                                                 // 0x4e seems to give 400Hz
    CCPTMRS1 = 0x1D;                                                            // PWM6 clocked by timer 6, PWM7 clocked by timer 2
    
    PWM6CON = 0x80;                                                             // enable PWM6
    PWM6DCH = 0x23;                                                             // 0x2300 seems to give 45% duty
    PWM6DCL = 0x00;                                                             // only top 2 bits used for fine control

    PWM7CON = 0x80;                                                             // enable PWM7
    PWM7DCH = 0x13;                                                             // 0x1300 seems to give 30% duty
    PWM7DCL = 0x00;                                                             // only top 2 bits used for fine control
    
    // main loop    
    while(1){       
    
    }
}
 
Last edited:

The NCP1247USBPDGEVB evaluation board is a flyback-topology switched-mode power supply designed for USB PD (power delivery) applications. The regulation of switched-mode power supply is ensured by the NCP1247 – a new fixed frequency current mode PWM controller [moderator action: removed link] CYPD1132-16SXI. The CCG1 Host Board from Cypress Semiconductor can be used for an easy demonstration how the power supply for USB PD application works. Communication between the NCP1247USBPDGEVB evaluation board and CCG1 Host Board is ensured by a USB Type-C cable (it uses the CC wire for communication and the VBUS wire for energy transmission).
 
Last edited by a moderator:

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top