CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Help need in implementation....

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
sanddune008



Joined: 23 Oct 2008
Posts: 38

View user's profile Send private message

Help need in implementation....
PostPosted: Thu Nov 20, 2008 6:27 am     Reply with quote

Hi All,

Problem statement:
I am struck writing code to encode bit. Using PWM and Timer0

It is as follows:

I have to retain pulses(38Khz) for duration = 13*(1/38Khz)
and keep no pulses for duration = 82*(1/38khz)



My Approach:

1. set up the PWM with duty cycle...etc for generating 38Khz pulses..
2. Parallel run the Timer0 with time duration equivalent of 13*(1/38Khz)
3. Inside the Timer0 ISR, I will make the corresponding associated CCP1 OFF and simultaneously set the Timer0 with new time duration of 82*(1/38khz) for which the CCP1 pin has to be low

Here i am struck how to proceed with timing a very important parameter.

Thanks to all in advance
sanddune008



Joined: 23 Oct 2008
Posts: 38

View user's profile Send private message

PostPosted: Thu Nov 20, 2008 8:00 am     Reply with quote

I tried following test code.........to start off with

What I am trying to achieve is encode a bit with following scheme.
Duration of 38khz pulses = 13* (1/38Khz)
and no pulses = 7 sec

Now the problem is i am not able to view the no pulses Duration on
the oscilloscope...I get a continuous 38Khz pulses.....Is it becos its too fast to view?Please correct me if i am wrong

Code:
#include <16F628A.h>
#use delay(clock=4000000)
void main(void)               //Program stepping point
{
   
   printf("\r\nInitialized\n\r");

//===========================================================   
   RED_LED_ON;
   delay_ms(1000);//Debug - remove this
   while(1)
   {                           

         SetPWM();
         delay_us(342);
         output_high(PIN_B3);
         delay_ms(7000);

   }
}

void SetPWM(void)
{
   set_tris_B(0x01);
   //App_init();
   setup_ccp1(CCP_PWM);   // Configure CCP1 as a PWM
   //setup_timer_2(T2_DIV_BY_4,249,1);
   setup_timer_2(T2_DIV_BY_1,25,1);
   //To generate 1khz PWM at 25% duty cycle at pin B3 CCP1
   //Generating 38Khz PWM with 50% duty cycle
   set_pwm1_duty(13);
}
sanddune008



Joined: 23 Oct 2008
Posts: 38

View user's profile Send private message

PostPosted: Thu Nov 20, 2008 8:52 am     Reply with quote

could someone explain..................
Rohit de Sa



Joined: 09 Nov 2007
Posts: 282
Location: India

View user's profile Send private message Visit poster's website

PostPosted: Fri Nov 21, 2008 12:43 am     Reply with quote

Quote:
SetPWM();
delay_us(342);
output_high(PIN_B3);
delay_ms(7000);
Once you set the PWM time base, you needn't keep setting it every time you run the loop.

Please read the PIC Midrange Reference Manual - http://ww1.microchip.com/downloads/en/DeviceDoc/31014a.pdf It will be of help.

I don't know if this will work, but you may try it:
Quote:
Section 14.5
Since the CCPx pin is multiplexed with the PORT data latch, the corresponding TRIS bit must be cleared to make the CCPx pin an output.
You can change the pin to an input when you don't want to output PWM on B3. It would be good practice to put a pull-up resistor on B3.

Rohit
sanddune008



Joined: 23 Oct 2008
Posts: 38

View user's profile Send private message

PostPosted: Fri Nov 21, 2008 2:26 am     Reply with quote

Thanks Rohit for your time...............

I am sorry......didn't put the entire code


I have connected an IR LED to the CCP1 pin(Pin B3) gate of FET .......Is this correct way? Can anyone give a working circuit?

I got the schematics from here
http://jap.hu/electronic/codec.html

Now what i am trying to achieve is an IR encoding of bit 1 and 0.
Encoding a bit:
I am setting the pwm for a know duration and setting the Pin B3 for a certain period. Is it possible to switch offf(set low) the CCP1 pin(B3).


Code:


Sendcommand()
{
SendBit0();
or
SendBit1();
}

void SendBit0(void)
{
   //printf("\r\nInsSndBit0\n\r");
   //38khz Pulses
   SetPWM();
   //delay_us(342);
   //modification after MPLAB simulation
   delay_us(322);
   //No pulses for 82*(1/38Khz)
   output_low(PIN_B3);
   delay_us(3130);//No pulses are sent     
}

void SetPWM(void)
{
   set_tris_B(0x01);
   //App_init();
   setup_ccp1(CCP_PWM);   // Configure CCP1 as a PWM
   setup_timer_2(T2_DIV_BY_1,25,1);
   //Generating 38khz PWM with 50% duty cycle
   set_pwm1_duty(13);
}



Basically a bit encoding..............Will this be an efficient mechanism?...
considering strict timing constraints. Following timing accuracy was tested using MPLAB Simulator.

Is there a way of achiving the same using only timers and PWM. If so how?

Thanks
sanddune008



Joined: 23 Oct 2008
Posts: 38

View user's profile Send private message

PostPosted: Fri Nov 21, 2008 7:50 am     Reply with quote

Is there a way to find whether IR Led is working or not?
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: Help need in implementation....
PostPosted: Fri Nov 21, 2008 9:07 am     Reply with quote

sanddune008 wrote:

I have to retain pulses(38Khz) for duration = 13*(1/38Khz)
and keep no pulses for duration = 82*(1/38khz)[/b]

My Approach:

1. set up the PWM with duty cycle...etc for generating 38Khz pulses..
2. Parallel run the Timer0 with time duration equivalent of 13*(1/38Khz)
3. Inside the Timer0 ISR, I will make the corresponding associated CCP1 OFF and simultaneously set the Timer0 with new time duration of 82*(1/38khz) for which the CCP1 pin has to be low

If I understand you correctly, you need to ensure exactly 13 PWM pulses and then exactly 82 PWM periods with no pulses. That can be measured out by letting PWM continue to run, but setting the duty cycle to 0%. If you use only Timer 0 to decide when to switch the duty cycle to zero, then you will eventually get 12 or 14 PWM pulses and 81 or 83 PWM time periods with no pulses. Somehow you need to synchronize your setting of the duty cycle with the Timer 2 timebase.

Here is one way: Start 38kHz PWM at 50% duty cycle and set Timer 0 to interrupt you in approximately 12.5 PWM periods of time (328 uSec). When you get the Timer 0 interrupt, change the duty cycle to 0%. The change will not take effect until the next PWM period is complete (13 time periods). But before you reload Timer 0, you must synchronize with Timer 2. This means you would busy-wait until Timer 2 resets at the end of the full 13 PWM time periods. Normally I would sooner eat worms than busy-wait in an interrupt routine, but in this case it might be acceptable. The time you need to busy-wait is small and known. It is less than 13 uSec. (half of 1/38kHz). Then set Timer 0 so it will interrupt you in 81.5 PWM time periods. When you are next interrupted, you can set the PWM duty-cycle back to 50% if you want.

Another way that does not involve Timer 0 is to count Timer 2 overflows. TMR2IF interrupt is set every time Timer 2 overflows, which in this case would be 26 uSec. If your clock speed is high enough, you may be able to write a short enough Timer 2 interrupt service routine that changed the duty-cycle after 13 or 82 interrupts.

If you need very fast access to the duty-cycle setting, as in the interrupt code just described, then you should not use the CCS library functions to do it. Instead use the #BYTE directive to define the hardware register addresses you need and write to them directly, such as:
Code:

#BYTE CCPR1L=0x15
   . . .
  CCPR1L = 0;  //..set duty cycle to 0%
   . . .
  CCPR1L = 65;  //..set duty cycle to 50% (assuming 20MHz clock)

_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: Help need in implementation....
PostPosted: Fri Nov 21, 2008 9:15 am     Reply with quote

[quote="RLScott"]
sanddune008 wrote:

I have to retain pulses(38Khz) for duration = 13*(1/38Khz)
and keep no pulses for duration = 82*(1/38khz)[/b]

My Approach:

1. set up the PWM with duty cycle...etc for generating 38Khz pulses..
2. Parallel run the Timer0 with time duration equivalent of 13*(1/38Khz)
3. Inside the Timer0 ISR, I will make the corresponding associated CCP1 OFF and simultaneously set the Timer0 with new time duration of 82*(1/38khz) for which the CCP1 pin has to be low

If I understand you correctly, you need to ensure exactly 13 PWM pulses and then exactly 82 PWM periods with no pulses. That can be measured out by letting PWM continue to run, but setting the duty cycle to 0%. If you use only Timer 0 to decide when to switch the duty cycle to zero, then you will eventually get 12 or 14 PWM pulses and 81 or 83 PWM time periods with no pulses. Somehow you need to synchronize your setting of the duty cycle with the Timer 2 timebase.

Here is one way: Start 38kHz PWM at 50% duty cycle and set Timer 0 to interrupt you in approximately 12.5 PWM periods of time (328 uSec). When you get the Timer 0 interrupt, change the duty cycle to 0%. The change will not take effect until the next PWM period is complete (13 time periods). But before you reload Timer 0, you must synchronize with Timer 2. This means you would busy-wait until Timer 2 resets at the end of the full 13 PWM time periods. Normally I would sooner eat worms than busy-wait in an interrupt routine, but in this case it might be acceptable. The time you need to busy-wait is small and known. It is less than 13 uSec. (half of 1/38kHz). Then set Timer 0 so it will interrupt you in 81.5 PWM time periods. When you are next interrupted, you can set the PWM duty-cycle back to 50% if you want.

Another way that does not involve Timer 0 is to count Timer 2 overflows. TMR2IF interrupt is set every time Timer 2 overflows, which in this case would be 26 uSec. If your clock speed is high enough, you may be able to write a short enough Timer 2 interrupt service routine that changed the duty-cycle after 13 or 82 interrupts.

If you need very fast access to the duty-cycle setting, as in the interrupt code just described, then you should not use the CCS library functions to do it. Instead use the #BYTE directive to define the hardware register addresses you need and write to them directly, such as:
Code:

#BYTE CCPR1L=0x15
   . . .
  CCPR1L = 0;  //..set duty cycle to 0%
   . . .
  CCPR1L = 65;  //..set duty cycle to 50% (assuming 20MHz clock)

Another thing that can speed up interrupt processing is to use the #INT_GLOBAL directive and write your own interrupt dispatcher, instead of using the CCS interrupt dispatcher and #INT_TIMER2. But if you do write your own global interrupt handler, then don't use any CCS library functions in the interupt code because you will have bypassed all the normal context saving that the CCS interrupt dispatcher does for you. You will be responsible for all context-saving. Look at the disassembly listing to be sure nothing is being used that might also be used in the main program.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
sanddune008



Joined: 23 Oct 2008
Posts: 38

View user's profile Send private message

PostPosted: Fri Nov 21, 2008 3:02 pm     Reply with quote

Thanks RLScott for your time.............

RLScott wrote:

Here is one way: Start 38kHz PWM at 50% duty cycle and set Timer 0 to interrupt you in approximately 12.5 PWM periods of time (328 uSec). When you get the Timer 0 interrupt, change the duty cycle to 0%. The change will not take effect until the next PWM period is complete (13 time periods). But before you reload Timer 0, you must synchronize with Timer 2. This means you would busy-wait until Timer 2 resets at the end of the full 13 PWM time periods. Normally I would sooner eat worms than busy-wait in an interrupt routine, but in this case it might be acceptable. The time you need to busy-wait is small and known. It is less than 13 uSec. (half of 1/38kHz). Then set Timer 0 so it will interrupt you in 81.5 PWM time periods. When you are next interrupted, you can set the PWM duty-cycle back to 50% if you want.


This is where I am facing problem ,

1. The IRcode scheme or protocol whatever contains multiple encode formats, OFF duration (No PWM pulses) varies based on the command (ex mycase: 0xAE) for bit 1, bit 0, extra burst pairs lead out , lead in,frame endseq all of them have same ON duration but differ in their OFF duration. In my case I have sent all of them bit0, bit1, Lead out burst ,Lead in burst seq and frame end seq

2. Now, I have check for whether it is bit 0 or bit 1 or lead out or lead in or seqence end in the Timer0 ISR and based on this Timer0 has to be loaded. With the OFF duration. won't that affect my timing though I set the timer to go off at 12.5 Pwm periods or 81.5...etc and Remember all the bit sequence(in a command) has to be at one go with no gap in between the command bits


RLScott wrote:

Another way that does not involve Timer 0 is to count Timer 2 overflows. TMR2IF interrupt is set every time Timer 2 overflows, which in this case would be 26 uSec. If your clock speed is high enough, you may be able to write a short enough Timer 2 interrupt service routine that changed the duty-cycle after 13 or 82 interrupts.


If you need very fast access to the duty-cycle setting, as in the interrupt code just described, then you should not use the CCS library functions to do it. Instead use the #BYTE directive to define the hardware register addresses you need and write to them directly, such as:
Code:

#BYTE CCPR1L=0x15
   . . .
  CCPR1L = 0;  //..set duty cycle to 0%
   . . .
  CCPR1L = 65;  //..set duty cycle to 50% (assuming 20MHz clock)

Another thing that can speed up interrupt processing is to use the #INT_GLOBAL directive and write your own interrupt dispatcher, instead of using the CCS interrupt dispatcher and #INT_TIMER2. But if you do write your own global interrupt handler, then don't use any CCS library functions in the interupt code because you will have bypassed all the normal context saving that the CCS interrupt dispatcher does for you. You will be responsible for all context-saving. Look at the disassembly listing to be sure nothing is being used that might also be used in the main program.



I need to try this approach......
I guess it would have been better if this would have been implemented in Assembly?

Thanks once again for your valuable guidance
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Fri Nov 21, 2008 6:34 pm     Reply with quote

Maybe the timing requirements are not so precise as you think they are. My guess is that your IRcode protocol will work fine even if you sometimes have 12 instead of 13 pulses, or 83 instead of 82 off-periods. If that is the case, then simply use Timer 0 to interrupt you when it is time to change from pulses to no-pulse or from no-pulses to pulses. After each period, make the calculations for what the next period should be (based on lead-in, lead-out, 1-bit, 0-bit commands, or whatever) and set Timer 0 accordingly. Do this before the next interrupt hits so you will not take too much time setting the duty-cycle when the time comes.

As for writing in assembly, if it turns out to be necessary, only write the small part in assembly that needs to be very fast. Use C for everything else. But before you write in assembly, write the interrupt code in C, compile it, and study the disassembly listing. This will do two things. First it will guide you in how you might write the assembly code, and second, it may convince you that custom assemble code is not necessary when you see how efficiently CCS does it.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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