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

corrupt/overwritten variable problem

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



Joined: 06 Jul 2007
Posts: 15
Location: Montreal Canada

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

corrupt/overwritten variable problem
PostPosted: Fri Aug 31, 2007 2:25 pm     Reply with quote

Hi,
I have a project where I use a PIC 16F627A to control a DC motor through an H-bridge. In the program I was having strange behaviour where it seemed that a variable I was using was being overwritten. I was able to simplify the program, and retain the behaviour. I have a small conditional section in my main loop, as follows:
Code:

         if(last_dir != REVERSE)
         {
            forward_end = false;         //reset forward end flag

            //since we have just changed direction, we need to soft start to take up the slack in the gears
            //otherwise we may cause unnecessary wear.
            soft_start_count = SOFT_START_TIME;         //reset the soft-start couner
            //reset the stall counter
            stall_counter = 0;
            last_dir = REVERSE;
            //turn the motor forward
            set_motor_state(BRAKE);
            //output_low(H_bridge_Input_A);   //set direction to brake to ground
            //output_low(H_bridge_Input_B);   //set input B for brake to ground
         }   

The first time through the loop, last_dir gets set. In my test code, this variable is never accessed anywhere else in the program, so this section should only execute once, however it is seemingly executed at random times. I did find that if I remove the set_motor_state() call, my problem went away. set_motor_state() was the only function other than main() in my program. It is small and simple, as follows:

Code:


void set_motor_state(int state)   //tells the motor to turn forward, backward or brake
{
   //set the signals to the motor chip based on the desired behaviour (forward/reverse/brake)
   if(state==FORWARD)
   {
      output_high(H_bridge_Input_A);   //set direction to forward
      output_low(H_bridge_Input_B);   //set input B for forward dir.

   }
   else if(state==REVERSE)
   {
      output_low(H_bridge_Input_A);   //set direction to reverse
      output_high(H_bridge_Input_B);   //set input B for reverse dir.

   }
   else if(state==BRAKE)
   {
      output_low(H_bridge_Input_A);   //set direction to brake to ground
      output_low(H_bridge_Input_B);   //set input B for brake to ground

   }

}
   



I am using PCM V4.042.

Does anybody have any ideas/suggestions? I would be happy to post the code, it is only 162 lines. (and half are comments or #defines.)
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Aug 31, 2007 3:06 pm     Reply with quote

Quote:
however it is seemingly executed at random times

1. Describe the H-Bridge circuit. Is it a separate chip ?

2. Describe the power and ground connections to the PIC and to the
H-Bridge chip or circuit. Is the PIC on a separate regulator from the
H-Bridge ?

3. Do you have a 100 nF ceramic capacitor on the PIC's Vdd pin
(close to the pin, and connected to ground) ?

See this thread about the importance of not "daisy chaining" the PIC
and the H-Bridge on the same power and ground traces, or wires.
http://www.ccsinfo.com/forum/viewtopic.php?t=29994
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sat Sep 01, 2007 5:00 am     Reply with quote

To rule out power supply problems try running the program without load connected, or connect a tiny load like a LED.
Or try running the program in a simulator, for example MPLAB.

If it is a software problem like a variable being overwritten then in C it is most likely another variable causing the problems, think of buffer overflows, etc. That's why we always ask people to post a complete program so we can check for such errors.
matt_at_hanbay



Joined: 06 Jul 2007
Posts: 15
Location: Montreal Canada

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

PostPosted: Sat Sep 01, 2007 6:58 am     Reply with quote

Thanks for the suggestions.

ckielstra, I will try your suggestion of removing the load when I return to work on Tuesday.

Quote:
1. Describe the H-Bridge circuit. Is it a separate chip ?

The H-bridge is an integrated unit from SL. It uses two logic lines, and a pwm input. It is a common chip.

Quote:
2. Describe the power and ground connections to the PIC and to the
H-Bridge chip or circuit. Is the PIC on a separate regulator from the
H-Bridge ?

In the layout we tried to sepperate the power/gnd nets for the driver and PIC. The PIC has it's own 7805 regulator.

Quote:
3. Do you have a 100 nF ceramic capacitor on the PIC's Vdd pin
(close to the pin, and connected to ground) ?

The PIC has a 0.1uF cap accross power/gnd near to the chip. Furthermore, I am fairly certain that the chip is not re-setting. I added a delay at the beginning of the program, so I could tell if it was re-setting, and it was not.

Quote:
See this thread about the importance of not "daisy chaining" the PIC
and the H-Bridge on the same power and ground traces, or wires.

I'll take a look at the thread, however we did our best to have a sepparate net for the driver and the PIC, both originating from powe supply source.

I will post the full code in a new post.

Thank you again for all help/suggestions. If we cannot resolve this, my boss wants me to re-write it in assembly!
matt_at_hanbay



Joined: 06 Jul 2007
Posts: 15
Location: Montreal Canada

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

PostPosted: Sat Sep 01, 2007 7:01 am     Reply with quote

Here is the full code as promised:
Code:


#include <16f627A.h>
//#include <16f886.h>
#fuses INTRC_IO,NOWDT,NOMCLR,NOPROTECT,NOLVP
#use delay(clock=4000000)


/*****************************************************
* in this area, we define the constants that we use in the
* program. These include step acceleration, etc.
*******************************************************/

//constants and pin definitions:
#define PWM_PERIOD_US      150         //set the pwm period to 200 micro seconds (5khz)
#define PWM_DUTY_CYCLE      100         //set the pwm duty cycle to 50%   
#define TICK_MS            1         //this is our approximate 'tick' time in ms
#define STALLED_THRESHOLD   400
#define SOFT_START_TIME      300         //the number of 'ticks' we should use reduced torque soft start for
#define SOFT_DUTY_CYCLE      10         //use 15% for soft start

#define FORWARD            1         //forward direction flag value use for eg. if(dir=FORWARD) etc
#define REVERSE            3         //reverse dirction flag
#define BRAKE            2         //stopped direction flag

#define MOTOR_PWM         PIN_B3      //motor driver h-bridge IC, PWM input-turns low side pwr transistor on and off

#define H_bridge_Input_A   PIN_A6      //motor driver h-bridge IC, InputA (INA) controls direction
#define H_bridge_Input_B   PIN_A7      //motor driver h-bridge IC, InputB (INB) controls brakeing

#define S_1               PIN_B4      //field effect switch 1
#define S_2               PIN_B5      //field effect switch 2

#define motor_current      PIN_A1      //motor current feedback

#define TTL_INPUT_1         PIN_B7      //ttl input 1
#define TTL_INPUT_2         PIN_B6      //ttl input 2

#define DIP_1            PIN_B2      //dip input 1
#define DIP_2            PIN_A0      //dip input 2
#define DIP_3            PIN_B0      //dip input 3
#define DIP_4            PIN_B1      //dip input 4
/*********************
* global variables
*********************/
int last_dir = REVERSE;                  //direction flag, 1=forward, 2=reverse, 0 = stopped
int forward_pullout = 0;
int reverse_pullout = 0;               //these counters are used to control full current pullout times
boolean forward_end = false;            //flag that shows that the actuator has reached the end of its travelenable flag for forward, set to false to stop motor in forward dir
boolean reverse_end = false;            //the given direction

long soft_start_count = 0;               //counter used for enabling/disabling soft starting torque

long stall_counter = 0;                  //this counter is used to keep track of how many 'ticks' it has been since the sensors changed state



/********************************************************************************
* This function handles setting the pins which control direction and braking signals
* to the motor control chip.
*********************************************************************************/
void set_motor_state(int state)   //tells the motor to turn forward, backward or brake
{
   //set the signals to the motor chip based on the desired behaviour (forward/reverse/brake)
   if(state==FORWARD)
   {
      output_high(H_bridge_Input_A);   //set direction to forward
      output_low(H_bridge_Input_B);   //set input B for forward dir.

   }
   else if(state==REVERSE)
   {
      output_low(H_bridge_Input_A);   //set direction to reverse
      output_high(H_bridge_Input_B);   //set input B for reverse dir.

   }
   else if(state==BRAKE)
   {
      output_low(H_bridge_Input_A);   //set direction to brake to ground
      output_low(H_bridge_Input_B);   //set input B for brake to ground

   }

}


void main()
{
   delay_ms(2000);

   set_tris_a(0b00000000);         //set direction of pins on port A,
   set_tris_b(0b11110000);         //set direction of pins on port B, only B3 (pwm signal) is output

   //outpt low on all unused output pins, so they are in a known state
   output_low(PIN_A0);
   output_low(PIN_A1);
   output_low(PIN_A2);
   output_low(PIN_A3);
   output_low(PIN_A4);
   output_low(PIN_A5);
   output_low(PIN_B0);
   output_low(PIN_B1);
   output_low(PIN_B2);

   output_high(PIN_B3);         //pwm debug

   disable_interrupts(GLOBAL);      //disable interrupts to start with

   //initialize variables
   last_dir = BRAKE;
   forward_pullout = 0;
   reverse_pullout = 0;

   //enable the internal pullups on port_b

   port_b_pullups(TRUE);   

   //enter our infinite loop waiting for signals

   for(;;)
   {

      port_b_pullups(TRUE);   
         //first, if we are changing direction, then we need to reset the reverse_end flag in case we are pulling away from the end
         if(last_dir != REVERSE)
         {
            forward_end = false;         //reset forward end flag

            //since we have just changed direction, we need to soft start to take up the slack in the gears
            //otherwise we may cause unnecessary wear.
            soft_start_count = SOFT_START_TIME;         //reset the soft-start couner
            //reset the stall counter
            stall_counter = 0;
            last_dir = REVERSE;
            //turn the motor forward
            set_motor_state(BRAKE);
            //output_low(H_bridge_Input_A);   //set direction to brake to ground
            //output_low(H_bridge_Input_B);   //set input B for brake to ground
         }

         //if we are continuing in the same direction, then we just decrement our soft-start counter
         else if(soft_start_count > 1)
         {
            soft_start_count--;            //decrement our soft-start counter
         }
         //when soft_start_count == 1, set the pwm duty cycle to normal torque... and reset soft_start_count
         else if(soft_start_count == 1)
         {
            soft_start_count = 0;         //reset so we don't execute this loop again   
            set_motor_state(REVERSE);   
            //output_high(H_bridge_Input_A);   //set direction to brake to ground
            //output_low(H_bridge_Input_B);   //set input B for brake to ground
         
         }
         //otherwise, we should be turning normally, so increment the stall counter
         else
         {
            stall_counter++;
         }

      delay_ms(TICK_MS);
   }
}
Ttelmah
Guest







PostPosted: Sat Sep 01, 2007 9:03 am     Reply with quote

The delay, may not show if the chip resets. The problem is that a 'brownout' reset, can leave the chip hung, or running part of the code it should never reach. The behaviour is not nice and determinate (reset, hence wll restart). I'm afraid the system almost certainly is getting spiked. Now you only talk about a 0.1uF across the chip. What capacitors have you got round the 7805?. These can be prone to oscillation, without reasonable amounts of output capacitance, placed right by the legs of the chip. What is the SL driver part number?.
I'd modify as follows:
1) Add a largish capacitor, right by the input of the 7805, and a small capacitor close to it's output. Consider adding a small inductor, in the lead feeding the power rail to the 7805.
2) Add two pull-down resistors to the lines feeding the two H-bridge drives. This ensures that both lines are in the 'brake' state, when the PIC is not operating.
3) Set the outputs to zero, before setting the TRIS.
As a comment here, you are using TRIS, but have not selected FAST_IO. Hence your settings, _will_ be being overridden by the compiler. Either use the fast_io mode, or give up on fiddling with TRIS. Personally, I'd switch to fast_io mode for this sort of application.
So:
Code:

output_a(0); //set all port a pins low
set_tris_a(0b00000000); //enable the outputs.

This way, the output latches are set low, _before_you enable the ports. At present, they will be in the default reset state (1), and you will momentarily set both H bridge inputs high. The same applies to port b.
Now, I'd look very carefully at your control switching. You descibe the unit as having a direction/enable control, but are operating it as if it is a standard H bridge (hence the question about part number). You need to ensure that all the state transitions are 'safe'. The combinations given, suggest that at times, you could end up with immediate switches in direction, which can lead to very high currents flowing. What motor overshoot protection is present, and what is it clamped to?. Is there a specified 'freewheel' state for the bridge?. If so, then change the direction switching code, to always select the freewheel state, and then the required power state.

Best Wishes
matt_at_hanbay



Joined: 06 Jul 2007
Posts: 15
Location: Montreal Canada

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

PostPosted: Sat Sep 01, 2007 9:41 am     Reply with quote

Ttelmah,
thank you very much for the suggestions. I don't have the schematic in on my laptop (it is at work), however I think it is essentially the same as the ST VNH3SP30-E http://www.st.com/stonline/products/literature/ds/12688.htm

I will check the capacitors that we have arround the regulator. We scope'd the ground/powr lines and they look OK, though there is some noise, it was definitely not oscillating. I think we will likely try adding an inductor to the power supply for the PIC as you suggest.

Quote:
The problem is that a 'brownout' reset, can leave the chip hung, or running part of the code it should never reach.

I did not know this, thank you for the info. Is there some way that I can check for this condition? How is this affected by enabling/disabling the brownout reset flag?

Quote:
Personally, I'd switch to fast_io mode for this sort of application.

I actually had fast_io enabled through much of my testing, but removed it as I simplified my code to try and make it as simple as possible. You make a good point about setting the output state before setting the tris registers.

This project is used to run a dc motor that is mounted on a metal assembly. The board is also mounted to the same assembly, and the PIC ground net is connected to the assembly (chassis). We found that the DC motor seemed to be inducing some AC noise into the chassis ground. Is it a no-no to have a PIC share the same ground as a DC motor?

We will be making major revisions to the PCB, so now is definitely the time to learn best practice.
matt_at_hanbay



Joined: 06 Jul 2007
Posts: 15
Location: Montreal Canada

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

PostPosted: Tue Sep 04, 2007 7:32 am     Reply with quote

Bump.
does anyone have any more ideas?

What is the best way to test for a buffer overflow in ccs?

Thanks again for all suggestions.
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