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

SPI timing issue???

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



Joined: 12 Jul 2007
Posts: 43

View user's profile Send private message

SPI timing issue???
PostPosted: Thu Mar 13, 2008 9:39 am     Reply with quote

We are working on a fluid dispensing machine that has valves open for so many milliseconds then closes them. This needs to be as accurate as possible, so we are using the timer 0 on the PIC18F97J60-based PICDEM.net 2 board. The issue we are seeing is that every so often, an entire valve block (on one serial driver chip, L9822E) will stay open for longer than it needs to, often causing an overflow.

Code "skeleton":
Code:

max_time = //maximum time any valve needs to be open;
elapsed_time = 0;
while(elapsed_time <= max_time)
{
     set_timer0();
     for(all instances of index)
     {
          if(valve_time[instance of index] == elapsed time)
               valve_command_changed = 1;
     }
     if(valve_command_changed)
     {
          send_valve_command(); //function that generates an SPI signal for all 16 daisy-chained driver chips
     }
     while(get_timer0()<3125); //25 MHz clock
     elapsed_time++;
}


The timer is setup with the correct values, the SPI signal is as slow as possible to ensure proper data transmission. The code mostly works (probably 99.9% of the time). I have examined the incoming data (written from ethernet to EEPROM to chip memory) to ensure it is correct when the error occurs.

I assume it is a timing issue since that data is all correct (the valve_time[instance of index] are correct as are the elapsed time and max time values. I have increased the "idle" time at the end of the code 10-fold and added the additional code to check if the valve needs to be off with little success. It seems to help in that there are fewer errors but that will kill accuracy.

Let me know if you have any thoughts on the matter. Thanks.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: SPI timing issue???
PostPosted: Thu Mar 13, 2008 10:09 am     Reply with quote

Your method of timing from Timer 0 looks a little unreliable. I assume that while(get_timer0()<3125); is supposed to wait for the rest of a specific period to expire. But that assumes you can always get through everything in that loop (including the SPI stuff) before 3125 ticks go by. Are you sure you can? Since you did not post the code for send_valve_command(), there is no way I can tell. Really, your skeleton is too abstract to be of much use. The problem is probably in some detail that you are omitting.

Robert Scott
Real-Time Specialties
javick82



Joined: 12 Jul 2007
Posts: 43

View user's profile Send private message

PostPosted: Thu Mar 13, 2008 11:23 am     Reply with quote

I apologize for the abstractness, but I want to avoid divulging all of my code over the 'net.

The send valve command writes a 16-byte wide "valve command" to the driver chips. The bits of the valve command are toggled appropriately and the function works. The bits in each element of valve_command are toggled appropriately.

Code:

void send_valve_command(void)
{
   int i;
   output_low(valve_driver_EN);
   delay_us(200);
   for(i = 0; i<16; i++)
   {
      spi_write2(valve_command[i]);
   }
   output_high(valve_driver_EN);
}


The timer0 was also my guess. I have increased the 3125 to 31250 and added the code to look for times that have elapsed in the 10 ms interval (instead of equality I use 2 inequalities). I am now implementing a longer timer tick (was using system timer/2, now am using system timer/8). I just can't think of any reason (there is no feedback in the "send_valve_command" function) that the MC would seemingly "hang-up" during this loop unless it passes over the timer. But I would think if it works once it would work every time because it always sends the same sized valve command.

The simplified loop is really all that I have, the index is just a 2-D array and there is one more check for another valve block's timing.

The time seems to be much greater than any of the times involved.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Fri Mar 14, 2008 8:15 am     Reply with quote

So each instance of send_valve_command() is essentially sending 16 bytes over the SPI. Your code shows setting valve_command_changed = 1, but I don't see where you are clearing it. If you don't clear it, you will continue to send unnecessarily forever.

Why do you say "all instances of index" instead of something definite like:

for(index=0; index<16; index++)

Is there something going on there that might be a problem?

Are you sure that all that set_timer0() does is set Timer 0 to 0x0000?

Is there any possible way that valve_time[0...15] could be changed within your main while() loop?

Something still doesn't make sense. You set valve_command_changed if any one of the valve_time[] entries equals elapsed time. But then you go and call send_valve_command(), which seems to do the same thing regardless of which valve_time[] ran out. Shouldn't your response to a valve_time running out depend on which valve_time it was that ran out? If not, then what is the harm in calling send_valve_command() all the time, whether things changed or not? That would simplify your loop for analysis, and perhaps point the way to where it is hanging up.

Robert Scott
Real-Time Specialties
javick82



Joined: 12 Jul 2007
Posts: 43

View user's profile Send private message

PostPosted: Fri Mar 14, 2008 8:50 am     Reply with quote

Sorry, I was just copying the code from memory. I am working on it from a different machine.

The valve_command_changed bit is reset at the top of each millisecond loop.

The 16-byte valve command is a global variable. Say I want to turn all valves on the 2nd daisy chained SPI chip on, I would leave all bits high except for the 15th of 16 bytes and "send_valve_command()", so commands are only sent as they need to be.

I have changed the scaling on my timer from 2 to 8 and modified the code to look at 4 ms windows which seems to, at the very least, mitigate the problem.

Is there another way, instead of the "while(get_timer0() <= 3125);" I can wait for the 1 ms (or whatever time period) to elaspe?
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Fri Mar 14, 2008 9:14 am     Reply with quote

javick82 wrote:
...Is there another way, instead of the "while(get_timer0() <= 3125);" I can wait for the 1 ms (or whatever time period) to elaspe?


Assuming that is your only problem, a more reliable way to detect 1 ms going by is to use the Timer 0 interrupt flag that gets set when Timer 0 rolls over from 0xFFFF to 0x0000. So your check becomes:
Code:

  while( ! INTCON.T0IF )    ;


and instead of setting Timer 0 to 0, you should
Code:

  TIMER0 = -3125;
  INTCON.T0IF = 0;

at the top of the loop. The exact form of INTCON.T0IF is probably different for your PIC18. I don't have the docs handy, but you can look it up.

Robert Scott
Real-Time Specialties
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