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

Programming multiple timing sensitive routines

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



Joined: 10 Apr 2007
Posts: 17

View user's profile Send private message

Programming multiple timing sensitive routines
PostPosted: Sun May 03, 2009 11:02 am     Reply with quote

I am working on a program on a 18F4550 where I need to read multiple ADC inputs and output a PPM stream that is 22.5MS in length with varying length pulse sequences. See pic below for reference.

I am trying to figure out the best way to code this to insure that I can output this sequence varying the pulse lengths from the ADC readings. So I basically need to be able to do the reads and calculations in between outputing this sequence insuring that I send out the PPM stream every 22.5MS.

Not sure if a State Machine, RTOS or just a loop is the way to go. There will be some calculations that need to be done to convert the ADC readings to the proper pulse lengths etc.

I will also be configuring the PIC via USB using HIDMaker FS from Trace Systems but that will not be at the same time that all the other stuff is going on.

Ideas?

bungee-



Joined: 27 Jun 2007
Posts: 206

View user's profile Send private message

PostPosted: Sun May 03, 2009 11:25 am     Reply with quote

You post similar theme a week ago.
On second hand, you never stated how many inputs/servos will you be reading/driving.
StealthMicro



Joined: 10 Apr 2007
Posts: 17

View user's profile Send private message

PostPosted: Sun May 03, 2009 12:02 pm     Reply with quote

It was a different question last week. I did figure out a good way to generate the PPM stream now with a large help from your post.

Now I am concerned with timing and putting it all together without missing any streams. So far in my head the best thing I can think of is to do the adc calculations and extra work during the long pause in the PPM signal. The signal needs to be 22.5MS in length and using 8 channels which is the max for PPM and if you maxed out their timing at 1.7MS each with the .3MS interval between each pulse that gives you 16MS which then leaves a minimum of 6.5MS for other things.

So would this work.

Setting up a timer to kick off at 22.5MS, sending the stream minus the long 6.5MS at its very shortest length setting the PIN high and then doing the other calculations at that time. Then when the timer kicks off again have it do the .3MS low as its first instruction.

Reading even 8 ADC's with 10us settling times each and doing the needed calculations should not come anywhere near 6.5MS.

Or am I wrong in my thinking here?

I will actually be reading 5 ADC channels and several digital signals to produce the PPM stream.

I will try it and see how it goes unless anyone else has a better idea than that.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sun May 03, 2009 12:36 pm     Reply with quote

To my opinion, you basically answered the question yourself: Using fast ADC timing, you can perform all necessary actions from the timer interrupt routine that assembles the ppm stream. By the way, you didn't clearly state what's the role of the 22.5 ms interval. I understand, that it's the signal's repetition period, not shown in your waveform?
bungee-



Joined: 27 Jun 2007
Posts: 206

View user's profile Send private message

PostPosted: Sun May 03, 2009 2:38 pm     Reply with quote

You could use timer to send the signal and main loop for ADC. By my opinion it enough that all the channels refresh each second interval.
So the code in the timer ISR stays like that and then in some main loop you just read the values of the ADC and set the global variables. ADC timing can be set to 4us - that is enough for one read, if I remember correctly there is a "wait" period before new read on other channel.

If you write your ISR timer routine in a way, that ADC value directly corelate to time, than you do not need a lot of calculating to do. And another thing ... you are using 48MHz clock --> ~84ns per instruction. I think that you have plenty of time here (77300 instructions in 6.5ms) Wink
StealthMicro



Joined: 10 Apr 2007
Posts: 17

View user's profile Send private message

PostPosted: Mon May 04, 2009 5:47 pm     Reply with quote

I started to think along those same lines. I got to thinking I could probably pull each channel during the .3MS pause between each channel thus leaving more processing power for even more things.

Is there a good way to determine exactly how many computing cycles things take in CCS like you can with ASM? That way I could calculate exactly how long it takes to do the various reads and calculations and subtract that from a very short delay_us or delay_cycles to make up the rest of the .3MS I need for the pulse pause.

Good idea or bad?
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Tue May 05, 2009 12:07 am     Reply with quote

MPLAB SIM can give exact (cycle accurate) timing information for your code. Another option is to synchronize the code execution to a hardware timer in a loop that waits until an absolute or relative time has been reached.
bungee-



Joined: 27 Jun 2007
Posts: 206

View user's profile Send private message

PostPosted: Tue May 05, 2009 1:00 am     Reply with quote

To know how long some operation takes, you can look at the asm listing. Or you can simulate it trough MPLAB and check timings there. And in the end you could still insert ASM code directly to your program.

I would not put ADC operation inside the timer interrupt routine, that would be a must if you want to catch that .3ms pause.

Write your program and test it, that is the best way to find out if it is working like you wish.

About good or bad idea .... well it is working like you wish, than is good ;)
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Tue May 05, 2009 6:48 am     Reply with quote

Is there a minimum pulse width, like for an RC servo? If so maybe you can start the pulse for channel n, then read the A/D(n), then setup the A/D for channel n+1, then do math on the reading(n) and decide how much longer the pulse should be, then end the pulse, then do it all for the next channel.

It would be a nice modular organization if the minimum pulse with is long enough to do the work.
_________________
The search for better is endless. Instead simply find very good and get the job done.
StealthMicro



Joined: 10 Apr 2007
Posts: 17

View user's profile Send private message

PostPosted: Tue May 05, 2009 3:50 pm     Reply with quote

SherpaDoug,

That would actually also be a good idea. I was thinking of using the .3MS pause between pulses but the minimum pulse width is .7MS so your idea would gain an additional .5MS to work inside of.

I shall try to put this all together. What is strange is no one has put this type of code up before and I believe it would help a lot of people. There are some modules like the PCTX module that interfaces a USB port on your computer to the buddy box port on a transmitter which is kind of like what I am doing and they use the exact same 18F4550 so I know it works. They also have another device just like it that does 24 individual servos using the same processor which would require more timing so it absolutely can be done without question.

You all have been a great help on this. I will post the code I come up with for assessment and possible optimization once I have it at least working as it should be.
DEsterline



Joined: 25 Aug 2009
Posts: 6

View user's profile Send private message

PostPosted: Sat Nov 14, 2009 4:46 am     Reply with quote

I know this is an old post, but this might help somebody...

There's another way to do this. Nothing in the hardware or software requires timer interrupts to be spaced evenly. In the interrupt routine you can reload the timer variable to adjust the time to the next interrupt.

Look at your desired waveform and imagine an interrupt at every transition. Using numbers I guessed from your waveform, first interrupt: set the pin low and reload for a 500uS interrupt. Next interrupt, set the pin high and reload for a 1500us interrupt. And on and on, in the last interrupt of the sequence, set the pin high and reload a calculated value that's (TotalCycleTime - SumOfAllTheOtherTimes) to ensure that your repetition rate is constant.

Depending on how you code it, the interrupt could be very fast, perhaps a dozen or so instructions. I would suggest something along the lines of:
toggle pin
timer_val = CalculatedTimes[SequenceState++]
bounds check SequenceState

The main loop code would be responsible for gathering data and computing the reload values.

Depending on how critical the repetition rate is, there may be an issue with allowing the main code to update the values during the cycle. Say it updates just before the last interrupt of the cycle. The SumOfTimes is based on the old data, but the new reload value is based on the new data. It could be off by some amount. (how much depends on a lot more things than I can discuss here)

Some systems may be entirely tolerant of that jitter and it's not a problem. But if you need to hold tighter timings there are a couple options. You can keep a running sum in the interrupt and compute the final reload value on the fly. Or you could create a semaphore system that only allows the variables to change after the last interrupt, before the new sequence begins. Perhaps two copies of the calculated values, a Calculating set and a Using set - then switch them every cycle.


There's lots of possibilities to optimize this method depending on your system priorities (RAM, Code Space or Speed). But the variable time interrupt method can produce your waveform with well under 1% processor loading, leaving lots of time for the main loop to do the heavy lifting.

Good luck.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

it all depends
PostPosted: Sat Nov 14, 2009 7:59 am     Reply with quote

U don't reveal the time relationship between ADC reading sets --
and any relationship time wise - to the output WFM U want to generate or if ther even IS any at all.
i've done just this sort of thing before - only w/o the funny output WFM

i would generate the WFM from a timer INT - using multiples counted down
for the longer duration - then use the timer edge to do a state machine for the ADC readings - even during the interval of what is NOW WFM output.

with states on subsequent timer INTS like
1- set ADC chan
2- start convert
3- get adc val
4- Increment ADC chan / modulo chans 2 read && set state back to #1

the clock cycle overhead from this approach is VERY low - on each timer INT cycle

i have used this method to get 4 interleaved ADC reading sets for use in an implantable medical pump servo with very good results .
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