CCP module - PWM mode - c

I'm trying to make a PWM output with this code, but apparently something is missing. Because when I check the Logic Analyzer in MPLab, nothing happens on CCP2 output. I'm working with the pic18f25k80.
void main() {
// Set up PWM
CCP2CON = 0b00001100; // Enable PWM on CCP2, bits 5:4 are LSB part of duty cycle
CCPTMRS = 0b00000000; // Use timer2 for all CCP modules
CCPR2L = 31; // MSB part of duty cycle
TRISC = 0b00000000; // Set port C as output
PORTC = 0; // Clear port C
// Set Up timer2
PR2 = 249; // PWM period = (PR+1)*4*Tcy = 1ms
T2CON = 0b00000100; // Enable TMR2 with prescaler = 1
while(1)
{
}
}
I expect when
TMR2 = PR2, CCP2 output toggles and timer is reset
further, TMR2 = CCPR2L (duty cycle), CCP2 output toggles
TMR2 keeps counting until step 1 is reached.
I suppose this is what should happen automatically. I mean I don't have to write the code for that, because that's THE function of the PWM module, right?
What am I missing?

Additional info:
TMR 2 is counting.
When I add PORTC = 0xFF; in the while loop and debug the code again. All signals on Port C are set, except RC2 (RC2 = corresponding output of CCP2).
When I try the same code for CCP3, all signals on port C are set, except RC2 and RC6 (RC6 = corresponding output of CCP3).
When I replace PORTC = 0xFF; with PORTCbits.CCP2 = 1;, only RC1 is set high.
Does this last bullet mean that the CCP2 is muxed with RC1 instead of RC2?

Related

STM32F303VC Timer1 Complementary PWM Doesnt work

I use Timer 1 for creating Complimentary PWM Output. I Set all registers according to the STM32F3 Reference Manual. When i debug code, The Timer Counter counts very well but the TIM1_CH1 Output doesnt output anything.(Other Channel Outputs have the same issue)
Here is my code :
void Timer1_PWMInit()
{
//----------------Setup Timer 1 for 25khz Center Aligned PWM-----------------
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // Enable Timer 1 Clock
GPIOE->AFR[1] |= 0x20; // Set Alternate Function 2 For Timer 1 CH1 Output
TIM1->CR1 = 0; // Clear CR1 Register(Turn off Timer 1)
TIM1->CNT = 0; // Clear Timer Counter
TIM1->PSC = 0; // Set Timer 1 Prescaler to 1:1
TIM1->ARR = 320; // 40 us(25 khz) PWM Period
TIM1->CCR1 = 320; // Timer 1 Channel 1 Duty Cycle(%50)
TIM1->CCR2 = 320; // Timer 1 Channel 2 Duty Cycle(%50)
TIM1->CCR3 = 320; // Timer 1 Channel 3 Duty Cycle(%50)
TIM1->CCR5 = 0; // Timer 1 Channel 5 Duty Cycle
TIM1->CCMR1 = 0x6868; // Set Channel 1 and Channel 2 Output Compare mode to PWM Mode
TIM1->CCMR2 = 0x68; // Set Channel 3 Output Compare mode to PWM Mode
TIM1->CCMR3 = 0x10048; // Set Channel 5 Output Compare Mode to Combined PWM Mode
TIM1->CCER = 0x10555; // Enable Output Compare Channels
TIM1->CR1 = 0xE0; // Set Counting Mode to Center Aligned Mode
TIM1->EGR |= 0x1; // Set UG bit for Updating Registers
TIM1->BDTR = 0xC800; // Set MOE and OOSR bits for enabling Output
TIM1->CR1 |= 0x1; // Enable Timer 1
//-------------------------------------------------------------------------
}
Try to enable GPIOE clock using 'RCC_AHBENR_GPIOEEN' and also set alternate function for the other timer channel output pins.

Whilst having my INT0 initialized as digital Input, it still gives out 2.8V which makes the Button don't really making a change

My Problem is that I have a digital Input initialized on PORTB.0. On that Pin I have a button and a 100k Pull-down Resistor. When I run my Pic with literally nothing ( void main() {while(1){}} ) the Voltage level on this pin works as I want it to (0 to 3.3V). But after I test my programm and initialize as shown in the Code below, it's range goes from 2.8 to 3.3V.
I am using a PIC18LF2520 for my graduation work. I am Programming in MPlab V5.10 with the XC8 1.45 Compiler. I just want an Interrupt for my Button which lies on the RB0 Pin of the uP. The initialisations I made will be shown on the Code down below. I already worked a lot with this particular PIC, but I have never had such an Error before.
void main() {
init();
while(1) {
/*
if(isEXT0Set()) { //If the Button gets pushed
EXT0Int(); //Interrupt Function call
}
*/
}
}
void init() {
//PORT Definitions
TRISA = 0x00;
TRISB = 0xC3;
TRISC = 0x00;
//Oscillator Settings
OSCCON = 0x7F; //8Mhz; Internal Oscillator; INTOSC stable
//Interrupt Settings
INTCON = 0xF0; //Global Enable; Peripherals Enable; TMR0 Enable; INT0 Enable
INTCON2 = 0x64; //INT0 rising Edge; INT1 rising Edge; TMR0 High Priority
INTCON3 = 0x08; //INT1 Enable
ADCON1 = 0x0F; //set all Inputs to Digital ones.
//Timer Settings
T0CON = 0x86; //16-Bit; LtoH; 1/128
T1CON = 0x31; //2 8-Bit; FOSC/4; 1/8
T2CON = 0x07; //Postscaler 1/1; Prescaler 1/16;
TMR0H = 0xE1; //Setting TMR0 to 1 Second
TMR0L = 0x7B;
TMR1IE = 1;
TMR2IE = 0;
}
I expect that when I push the button that INt0IF will be set, but that doesn't happen. I testes it on the Hardware, the result is decribed up above. I hope someone sees what I missed. Thanks in advance. :D
PIC controller has internal pull-up resistors on PORTB and usually, they're much less than 100kOhm. You can turn all of them just changing INTCON2 initialization to:
INTCON2 = 0xE4;

I want to use interrupts in 32 bit PIC microcontroller.i'm getting output in MPLAB simulator but can not get it on my Explorer 16 kit

I'm using PIC32MX575F256L microcontroller. This is a simple program to turn on and turn of LED's connected to lower 8 bits of port A using a simple switch as external interrupt:
#include<p32xxxx.h>
#include<plib.h>
void __ISR(3,ipl4) EXTInterrupthandller(void) // interrupt handler
{
PORTAINV = 0x0ff; //toggle lower 8 bits of port A (LEDs)
IFS0CLR = 0x00000800; //clear the interrupt flag
}
main()
{
DDPCONbits.JTAGEN = 0;
TRISA= 0; // set port A as output port
TRISESET = 0x0200; // set external interrupt pin as input pin
PORTA = 0; // initially LEDs are off
IEC0CLR = 0x00000800; // disable INT3
IPC0SET = 0x10000000; // set priority and sub priority of interrupt
INTCONCLR = 0x00000004; // clear the bit for falling edge trigger
IFS0CLR = 0x00000800; // clear the interrupt flag
INTEnableSystemSingleVectoredInt(); // configure system to handle single vector interrupts
IEC0SET = 0x00000800; // enable INT3
while(1); // main loop
}

how to activate 16bit timer on AVR programming

I have an atmega168a chip. I use Counter 0 to toggle PORTC by using ISR(TIMER0_COMPA_vect) and ISR(TIMERB_COMPA_vect) interrupt sub-routines. I would like to activate the 16-bit timer when if condition is true. So, I use TIMSK1 = (1<<OCIE1A), but this line calls ISR(TIMER1_COMPA_vect) interrupt instantly where I want 16 bit timer to be interrupted only when the counter reaches to OCR1A value. How can I activate the 16-bit timer on the run-time without causing an instant interrupt?
here is my code:
#define F_CPU 8000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
volatile uint8_t counter;
int main (void){
DDRC = 0xFF; //sets PORTC as output
PORTC = 0xFF; //initial output value
/*COUNTER0 settings*/
TIMSK0 = ((1<<OCIE0A) | (1<<OCIE0B)); // Enable Interrupt TimerCounter0 Compare Match A & B
TCCR0A = (1<<WGM01); // Mode = CTC
TCCR0B = (1<<CS01) | (1<<CS00); // Clock/64, 1/(8000000/64)= 0.000008 seconds per tick
OCR0A = 200; // 0.000008 *230 = 1.6 ms
OCR0B = 100; // 0.8 ms
/*16bit timer - counter1 settings*/
TIMSK1 &= ~(1<<OCIE1A); // Disable Interrupt Counter 1, output compare A (TIMER1_CMPA_vect)
TCCR1B = ((1<<CS12) | (1<<CS10) | (1<<WGM12)); // Clock/1024, 1/(8000000/1024) = 0.000128 seconds per tick, Mode=CTC
OCR1A = 40; // 0.000128*40 ~= 5.12 milliseconds
sei(); //interrupts are globally switched on
counter =0;
while(1){
if(counter >= 4){
TCNT1 = 0; // clear the counter 1
TIMSK1 = (1<<OCIE1A);// Enables the interrupt for Counter 1,(TIMER1_CMPA_vect)
TIMSK0 &= ~((1<<OCIE0A) | (1<<OCIE0B)); //disables the Counter 0's interrupts
counter = 0;
}
}
return 0;
}
ISR(TIMER0_COMPA_vect){ //1.6ms
PORTC = 0xFF;
counter++;
}
ISR(TIMER0_COMPB_vect){ //0.8 ms
PORTC = ~PORTC;
}
ISR(TIMER1_COMPA_vect){ // 5.2 milisecond interrupt
PORTC = 0x00;
TCNT0 = 0; //clear the counter of counter0
// TIMSK0 = ((1<<OCIE0A) | (1<<OCIE0B)); //Enable the Counter 0 interrupts
// TIMSK1 &= ~(1<<OCIE1A);// Disable Interrupt Counter 1, output compare A (TIMER1_CMPA_vect)
}
here is an oscilloscope output that shows why I don't want the interrupt to be set instantly, because it set the signal 0 instantly.
I think the problem might be that in CTC mode, interrupt is generated when OCF1A flag is set (in TIFR). Since your timer is always running, just not generating interrupts, it sets OCF1A flag, which never gets cleared. On page 142 in the datasheet it says:
OCF1B is automatically cleared when the Output Compare Match B
Interrupt Vector is executed. Alternatively, OCF1B can be cleared by
writing a logic one to its bit location.
This means that when you set up timer 1, you also need to clear OCF1A:
TIFR1 &= ~(1<<OCF1A)
However, I think you can do better. You could just stop the timer when not needed, and start it when you do, instead of twiddling the TIMSK and having timer 1 run always. If you set TCCR1B to zero, that clears CS12, CS11, and CS10, which, according to the datasheet means "Timer stopped." Then, when your counter reaches 4 you can turn on timer1 as you have it above:
TCCR1B = ((1<<CS12) | (1<<CS10) | (1<<WGM12));
If you do this, you shouldn't need to turn timer 1 interrupts on and off: just leave them on, and only turn the counting on when you need it.
Also I am wondering if it is actually necessary to fire off two interrupts to toggle pins on PORTC? Are you not using PWM for that because it doesn't give you the pulse lengths precisely enough?

variable PWM setting in PIC24FJ64GA002

I am working on project in which I need to display different colors on RGB led. I am using pwm to drive different colors on LED. My Pic is PIC24FJ64GA004 with which I am working on now. Basic concept of this project is to use switch to controls colors.
Colors on RGB led will be according to days and month in year. For that I am using 7-segment led with switch to count days and month.
Problem at the moment is following code. I am trying to change PWM values by following settings. But instead of changing it it is giving me some thing weird.
I need your help guys. Could you please help me with this thing.
for( counter=0x0000;counter<=0x4571;counter++){
//*****Timer2 starting from here*****//
PR2 = 0x4571; // Initialize PR2 with 0x4571 = 17777 as PWM cycle
IFS0bits.T2IF = 0; // Clear Output Compare interrupt flag
IEC0bits.T2IE = 1; // Enable Output Compare interrupts
T2CONbits.TON = 1; // Start Timer2 with assumed settings
//**********************************//
//*****For RED LED OC1 choosed with timer 2*****//
OC1CONbits.OCM = 0; // Output compare channel is disabled
OC1R = 0x0000 ; // Initialize Compare Register1 with 50% duty cycle
OC1RS = counter; // Initialize Secondary Compare Register1 with 50% duty cycle
OC1CONbits.OCSIDL = 0; // Output capture will continue to operate in CPU Idle mode
OC1CONbits.OCFLT = 0; // No PWM Fault condition has occurred (this bit is only used when OCM<2:0> = 111)
OC1CONbits.OCTSEL = 0; // Timer2 is the clock source for output Compare
OC1CONbits.OCM = 0x6; // PWM mode on OC, Fault pin disabled
//*****For Green Led OC2 and OC3 Choosed with timer2 as well*****//
OC2CONbits.OCM = 0; // Output compare channel is disabled
OC2R =0x0000; // Initialize Compare Register1 with 50% duty cycle
OC2RS =counter; // Initialize Secondary Compare Register1 with 50% duty cycle
OC2CONbits.OCSIDL = 0; // Output capture will continue to operate in CPU Idle mode
OC2CONbits.OCFLT = 0; // No PWM Fault condition has occurred (this bit is only used when OCM<2:0> = 111)
OC2CONbits.OCTSEL = 0; // Timer2 is the clock source for output Compare
OC2CONbits.OCM = 0x6; // PWM mode on OC, Fault pin disabled
//*****For Blue Led OC2 and OC3 Choosed with timer2 as well*****//
OC3CONbits.OCM = 0; // Output compare channel is disabled
OC3R = 0x0000; // Initialize Compare Register1 with 50% duty cycle
OC3RS = counter; // Initialize Secondary Compare Register1 with 50% duty cycle
OC3CONbits.OCSIDL = 0; // Output capture will continue to operate in CPU Idle mode
OC3CONbits.OCFLT = 0; // No PWM Fault condition has occurred (this bit is only used when OCM<2:0> = 111)
OC3CONbits.OCTSEL = 0; // Timer2 is the clock source for output Compare
OC3CONbits.OCM = 0x6; // PWM mode on OC, Fault pin disabled
}
But this code is working alright. I put different values as well. It works fine.
//*****For RED LED OC1 choosed with timer 2*****//
OC1CONbits.OCM = 0; // Output compare channel is disabled
OC1R = 0x22B8; // Initialize Compare Register1 with 50% duty cycle
OC1RS = 0x22B8; // Initialize Secondary Compare Register1 with 50% duty cycle
OC1CONbits.OCSIDL = 0; // Output capture will continue to operate in CPU Idle mode
OC1CONbits.OCFLT = 0; // No PWM Fault condition has occurred (this bit is only used when OCM<2:0> = 111)
OC1CONbits.OCTSEL = 0; // Timer2 is the clock source for output Compare
OC1CONbits.OCM = 0x6; // PWM mode on OC, Fault pin disabled
//*****For Green Led OC2 and OC3 Choosed with timer2 as well*****//
OC2CONbits.OCM = 0; // Output compare channel is disabled
OC2R =0x22B8; // Initialize Compare Register1 with 50% duty cycle
OC2RS =0x22B8;//0x22B8; // Initialize Secondary Compare Register1 with 50% duty cycle
OC2CONbits.OCSIDL = 0; // Output capture will continue to operate in CPU Idle mode
OC2CONbits.OCFLT = 0; // No PWM Fault condition has occurred (this bit is only used when OCM<2:0> = 111)
OC2CONbits.OCTSEL = 0; // Timer2 is the clock source for output Compare
OC2CONbits.OCM = 0x6; // PWM mode on OC, Fault pin disabled
//*****For Blue Led OC2 and OC3 Choosed with timer2 as well*****//
OC3CONbits.OCM = 0; // Output compare channel is disabled
OC3R = 0x22B8; // Initialize Compare Register1 with 50% duty cycle
OC3RS = 0x22B8; // Initialize Secondary Compare Register1 with 50% duty cycle
OC3CONbits.OCSIDL = 0; // Output capture will continue to operate in CPU Idle mode
OC3CONbits.OCFLT = 0; // No PWM Fault condition has occurred (this bit is only used when OCM<2:0> = 111)
OC3CONbits.OCTSEL = 0; // Timer2 is the clock source for output Compare
OC3CONbits.OCM = 0x6; // PWM mode on OC, Fault pin disabled
//*****Timer1 starting from here*****//
PR1 = 65535; // Initialize PR2 cycle
T1CONbits.TCKPS = 2; // Setting pre-scaler to 1/64
IFS0bits.T1IF = 0; // Clear Output Compare interrupt flag
IEC0bits.T1IE = 1; // Enable Output Compare interrupts
T1CONbits.TON = 1; // Start Timer1 with assumed settings
//*****Timer2 starting from here*****//
PR2 = 0x4571; // Initialize PR2 with 0x4571 = 17777 as PWM cycle
IFS0bits.T2IF = 0; // Clear Output Compare interrupt flag
IEC0bits.T2IE = 1; // Enable Output Compare interrupts
T2CONbits.TON = 1; // Start Timer2 with assumed settings
//**********************************//
You are updating your PWMs each time around the loop.
It's very unlikely that the counter has had time to expire, therefore you keep resetting it before it has chance to "do" a PWM cycle.
At the end of the loop, you need to wait for (at least one of) your PWMs to have expired.
An alternative way might be to set up the next value you want in the loop and have an interrupt service routine copy that to the PWM register when the timer expires. And once that has happened, you can set up the next next value :) You need to take care about how you transfer values between the main loop and the ISR as they are effectively different "thread" contexts.

Resources