|
|
View previous topic :: View next topic |
Author |
Message |
matt_at_hanbay
Joined: 06 Jul 2007 Posts: 15 Location: Montreal Canada
|
corrupt/overwritten variable problem |
Posted: Fri Aug 31, 2007 2:25 pm |
|
|
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
|
|
Posted: Fri Aug 31, 2007 3:06 pm |
|
|
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
|
|
Posted: Sat Sep 01, 2007 5:00 am |
|
|
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
|
|
Posted: Sat Sep 01, 2007 6:58 am |
|
|
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
|
|
Posted: Sat Sep 01, 2007 7:01 am |
|
|
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
|
|
Posted: Sat Sep 01, 2007 9:03 am |
|
|
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
|
|
Posted: Sat Sep 01, 2007 9:41 am |
|
|
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
|
|
Posted: Tue Sep 04, 2007 7:32 am |
|
|
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. |
|
|
|
|
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
|