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 support@ccsinfo.com

Need help writing to custom bus protocol

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



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

Need help writing to custom bus protocol
PostPosted: Thu May 11, 2006 2:35 pm     Reply with quote

Hi,

I'm working on a project that requires me to read in and write on a 1 wire serial communiction. Its a stupid old system that was proprietary and no one has done anything like it I beleive. Its very similar to OBD2 VPW but not exact, uses different timings, voltage, data length, crc etc

The problem I have is my board has to be taking adv readings and toggling/checking digital pins on a timed basis (my shortest event is every 2ms). So while I'm doing all this other stuff I'm finding it difficult to find the time to read in this bus and when I go to write out to it, I block the chip from doing anything till I'm done bit banging the signal out.

For example, my write code (which is WAY more important then reading, but I'de like to do both):

// S = 200us
// L = 400us

//Start writing
output_high(BUS); delay_us(L); //1
output_low(BUS); delay_us(L); //0
output_high(BUS); delay_us(S); //0
output_low(BUS); delay_us(L); //0
output_high(BUS); delay_us(S); //0
output_low(BUS); delay_us(S); //1
output_high(BUS); delay_us(S); //0
output_low(BUS); delay_us(S); //1
... etc etc
output_high(BUS); //done

//go back to doing stuff now,

I know it doesn't seem like much, but those uSeconds add up. I think this should be possible without using delays.


I'm trying to figure out a way to not block the chip while I'm writing. My longest side task takes me 30us. So I spend a lot of time in the main loop not doing anything, I figure maybe I could set a flag like WRITE_DATA=TRUE, and then have a few bytes of data stored somewhere I could passively bit bang out.

I know this is possible but I've had a hard time figuring out what I need to do,

Anyone have any suggestions ?? A passive read() part is next,
Thanks!

(using pic 16F87X but could switch if needed)
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Thu May 11, 2006 3:08 pm     Reply with quote

I had a similar issue. I have two processors - one is concerned with the user interface, and the other is locked away in a vault. They communicate via CAN bus.

The user interface processor has an IR decoder to allow 'pass through' of IR commands from a standard remote control. The user can use the remote to be able to control some A/V equipment locked away in the vault. The user interface processor receives/decodes/compresses the IR bitstream and sends it to the remote processor via the CAN bus. Once all information necessary to reconstruct the IR bitstream has been received by the remote processor, it then starts to "beam" that information to the A/V equipment.

This is where our situations are similar. I couldn't use an approach that involved delays because this processor also communicates with many other processors, and requests for information can come at any time and must be serviced immediately (more or less). When those requests come, they can't interfere with the IR transmission either because that would result in a miscommunication with the A/V equipment (and that can't be tolerated).

What I did was set up a rather complicated but very robust algorithm involving a timer interrupt. The general idea is that you load the data that must be transmitted, set the output pin appropriately, and set the timer to go off at the appropriate time (which for you appears to be either 200 us or 400 us). You also load the next timer value at this point in time as well to speed things along the next time the interrupt occurs. When the timer interrupts, you toggle the state of the output pin, reload the timer with the value you 'set aside' earlier, and load the timer value for next time. This goes on until you're done sending the information.

There is a rather small latency between when the interrupt fires and the processor actually gets around to servicing the interrupt, but this time should be more or less the same no matter what the processor is doing. The net effect is that the timing accuracy on your output waveform is relatively good. There will be some jitter, but that will be relatively small.

I can't really elaborate more as this is proprietary stuff, but you should get the idea.
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Thu May 11, 2006 4:09 pm     Reply with quote

Hey newguy,

Yea I know what your talking about, thats kind of what I had planned.

If I'm in a 20us delay for my adc and the timer goes off it will still jump to the timer_isr right ? I don't know if I've ever had to check what happens to an interupt request when the pic is in a loop, pretty sure it would jump...

Hmmmmmm..... I could set that up.

Are you setting a flag in the interupt that the main loop checks later and changes the data or are you doing all the work (shifting next data bit, reloading timer, changing output state) there inside the isr? I could do the later although I think its against recommended practice, and I'd have to make my data global.

I'll have to think about this for a bit, I'll certainly try it tho.

One thing is I can see it handeling the writes, reads may be another issue tho.
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Thu May 11, 2006 4:38 pm     Reply with quote

iso9001 wrote:
Hey newguy,

Yea I know what your talking about, thats kind of what I had planned.

If I'm in a 20us delay for my adc and the timer goes off it will still jump to the timer_isr right ? I don't know if I've ever had to check what happens to an interupt request when the pic is in a loop, pretty sure it would jump...

Hmmmmmm..... I could set that up.

Are you setting a flag in the interupt that the main loop checks later and changes the data or are you doing all the work (shifting next data bit, reloading timer, changing output state) there inside the isr? I could do the later although I think its against recommended practice, and I'd have to make my data global.

I'll have to think about this for a bit, I'll certainly try it tho.

One thing is I can see it handeling the writes, reads may be another issue tho.


I'm not sure about an interrupt being able to break out of a delay loop. Depends how the compiler handles it. My gut says that it should happen this way, but I wouldn't count on it.

The timer interrupt itself just takes whatever the next delay value is (which is set in the main routine) and adds that to the current value of the timer. Check the code library for a little writeup called "timers - what you should know" that I posted as to why I do it in this manner if it doesn't make sense. The interrupt then sets a flag that the main routine uses to load the next value that the interrupt will need the next time it fires. I think that the load routine also sets a "all done" flag that deactivates everything if no more data is waiting to be clocked out. That's about it. It sounds like the timer interrupt is doing a lot, but it really isn't. All it does is toggle the output line, reads the current value of the timer, adds the next delay value to it, and reloads the timer with this new value. It then sets a flag, and it's done. Not very many instructions at all, so the timer interrupt is quick.

I had to break up data retrieval (i.e. the next timer value) and setting the timer like this because an IR data stream isn't a simple thing to reconstruct. Fetching the next timer value isn't a simple matter because it can vary a lot (i.e. it's not fixed as x for a 1 and y for a 0). It sounds like your app is simple enough to be able to do everything inside the timer isr.

The best way to handle the reads would be using an external interrupt pin or the interrupt-on-change, if the way things are wired allows it, or if you can rewire it in this manner. Then just coordinate changes in pin state with a free running timer and figure out your 1's and 0's from that information. If not, then you pretty much have to poll the input pin in main.

Polling becomes more of a pain, but you can still use a timer to try & figure out the bit times - it's just that the values you read will have more jitter which will make deciding what is what a bit more difficult. My polling algorithm idea is this:

in main() have this:

Code:
if (input(COMM_PIN) != last value) {
   last_value = input(COMM_PIN);
   start_inactivity_timer();
   read_and_save_timer_value();
}


You'd also need another timer interrupt (I called it the "inactivity timer"). The basic idea being that while data is coming, the inactivity timer acts like the watchdog - every time you get a change/bit, "pet" this watchdog. If a long period with no activity on the comm line goes by, this timer expires and then you can examine the timer values you saved when data was coming in. From those values, you should be able to determine 1's and 0's.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Thu May 11, 2006 5:45 pm     Reply with quote

Use the CCP for your transmission. Create a state machine and load a CCP value that represents your delay time. Somewhere in your code you would start the transmission. The would reset the state machine and enable the CCP interrupt. Now your program can resume operation and the transmission will be handled by the interrupt.
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