Category Archives: Stellaris

Stellaris LM3S

Code Composer Studio Graphing Tool Tutorial

 

In this Code Composer Studio graphing tool tutorial, graphing variables will be demonstrated in Texas Instruments IDE.  The process is fairly straightforward and will be shown in a video as well as some screenshots so it can be easily replicated.

Introduction

For the demonstration a program running on the MSP430G Launchpad was used, with the MSP430G2553 fitted.  The Launchpad was connected to a small experimental PID boc I have constructed, which I call the ‘Pocket PID’ (tutorial to follow on this), the box uses a LM35DZ temperature sensor as well as a few other components.  The voltage from the LM35DZ is sampled and then two variables are generated; a variable called Result which is comprised of a raw data set of several over samples and a variable called FilteredResult, which is a digitally filtered version of the Result variable.  Both variables can be viewed side by side which allows the effectiveness of the digital filter to be observed, the box also has a small heater and fan which allows the variables rate of change to be viewed over time in a graphical format. This provides a good example of how the code composer studio graphing tool can be used.

The graphing tool can also bee seen in action on another tutorial based on the C2000 Launchpad, where it is used to view the operation of an solar MPPT, graphing the power, voltage and PWM duty cycle.  The third part of the article concerned with this can be found here and the YouTube video here.

Code Composer Studio Graphing Tool Tutorial – Video Demonstration

Code Composer Studio Graphing Tool Tutorial – Main Steps

The main steps to access the the graphing tool in code composer studio (CCS) are carried out in debug mode, so all the screenshot images below are taken from within that mode.  As with all software there are often other ways to achieve the same results, this is just a method that works for me.

The first step is to decide which variables you want to graph and add these as Watch Expressions in CCS, this is achieved by highlighting the variable and then right clicking to bring up a properties menu, from this menu you want to choose the Add Watch Expression selection. This is shown in the below image.

Code Composer Studio Graphing Tool Tutorial Add Watch Expression MSP430 Tiva C C2000

If this has been successful then the variable chosen should then appear in the Expressions window, which is shown in the next image.

Code Composer Studio Graphing Tool Tutorial Watch Expression Visible MSP430 Tiva C C2000

You can add as many watch expressions as necessary, the video demonstration shows two variables being watched and graphed, but I have successfully watched and graphed four expressions.  I am not sure if there is an upper limit, but i have noticed stability issues when many variables are being watched over a long period of time.

After adding the variables required to the watch expression window, the next step is to add breakpoint and then edit the breakpoint properties.  Adding a breakpoint can be achieved either by double clicking on the line number, or highlighting a section of code on the line number and right clicking, then selecting the Breakpoint (Code Composer Studio) and Breakpoint option.  The image below illustrates this action.

Code Composer Studio Graphing Tool Tutorial Add Breakpoint MSP430 Tiva C C2000

Once the breakpoint has been added it should be visible in the Breakpoint window, for the breakpoint to be enabled it needs to have a tick in the far left column.  The image below shows the breakpoint window with the tick in the far left column, as well as an arrow highlighting the Action column.

Code Composer Studio Graphing Tool Tutorial Breakpoint Visible MSP430 Tiva C C2000

 

A breakpoint by default will halt the program at the chosen point, for the graphing tool to work all the windows simply need to be refreshed, this then allows the Expressions window and the graph to be updated.  The next image illustrates how this is achieved by editing the breakpoint properties.  I simply right click on the breakpoint symbol shown next to the line number it will activate, this then brings up a properties list and then select the Breakpoint Properties option. The image below shows this then step.

Code Composer Studio Graphing Tool Tutorial Breakpoint Properties MSP430 Tiva C C2000

Once the Breakpoint Properties window is open there are a few options that are accessible, for this tutorial only one is of interest which is the Action property.  As already mentioned the action the breakpoint will carry out by default is half the program, for the watched expressions to update, this action simply needs to be changed to Refresh All Windows.  The next image illustrates how this is changed.

Code Composer Studio Graphing Tool Tutorial Breakpoint Properties Change Action MSP430 Tiva C C2000

 

Now that the variables have been added and a breakpoint has been placed and set-up to perform the required action, the variables to be graphed can be chosen and set-up.  To bring a graph up for a particular variable, right click on the variable in the Expressions window and then select the option Graph,  as per the image below.

Code Composer Studio Graphing Tool Tutorial Watch Expression Right Click MSP430 Tiva C C2000

Once the graph option is selected the graph should be visible in CCS, I find it usually defaults to the bottom left of the window, as shown in the next image.  The graph window can be manipulated to the required size as well as being picked and placed as required.  Additional graphing windows can be added for other variables in the same way.

Code Composer Studio Graphing Tool Tutorial Tutorial Add Graph Window MSP430 Tiva C C2000

Now the graphing windows also has various options which allow you to tailor the view for your requirements, by hovering over the symbols small tooltips will appear which give a good impression of the button’s action.  This tutorial will only cover two of the buttons which provide enough of an introduction for now.  The first button is the Graph Properties button which is shown in the image below.

Code Composer Studio Graphing Tool Tutorial Graph Properties MSP430 Tiva C C2000

By clicking this button a new window will open which displays some useful quick access properties.  I usually use the Grid Style option to add a Major Grid to the x and y axis, additionally the Display Data Size option allows you to determine how much data is viewable on the graph, before it is pushed off the edge of the screen.  For long data captures increasing the Display Data Size can be useful, I have had issue with instability here though so its compromise on other settings such as Sampling Rate Hz as well as other settings for CCS when in debug mode.  The Graph Properties window is shown in the next image.

Code Composer Studio Graphing Tool Tutorial Tutorial Graph Properties MSP430 Tiva C C2000

The next button that will prove useful is the Graph Display Properties button, this is shown in the next image (also note the Major Grid now shown on the graph window).

Code Composer Studio Graphing Tool Tutorial Graph Display Properties MSP430 Tiva C C2000

The Graph Display Properties window again has quite a few options, allowing things like colour, number formats, axis names and scale to be changed.  Some of these options are demonstrated in the video, the image below shows the Graph Display Properties window and the option for the Y axis Set Number Format option window open.

Code Composer Studio Graphing Tool Tutorial Graph Display Properties MSP430 Tiva C C2000

The final image shows a screen capture from the video, with both sets of data displayed side by side.

Code Composer Studio Graphing Tool Tutorial Video Result Capture MSP430 C2000 Tiva C

I take great care when writing all the tutorials and articles, ensuring all the examples are fully tested to avoid issues for my readers.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

Switch Debouncing Tutorial Pt/2

 

In this switch debouncing tutorial part 2 C code debounce algorithms will be looked at further, and their effectiveness.  All the software solutions shown will be demonstrated on the MSP430G Launchpad.  However the basic principle of operation shown in the examples, can be applied to all microcontrollers, particularly the last example which is based on some code found at Jack Ganssle tutorial, this can be easily implemented on any system using the C language.

MSP430 Single Switch Debounce WatchDog

The first debounce algorithm example is based on some Arduino code, which uses the millis() function.  In this case the millis second count is generated by the watchdog timer on the MSP430.  The launchpad switch connected to GPIO P1.3 is used in this test code.

The while loop on line 1 is inside the main function, line 5 AND’s port 1 with BIT3 as this is the only GPIO pin of interested.  Lines 6 to 9 will set the variable reading to a 1 if the value on pin P1.3 is a 1 i.e. not pressed, and 0 if the switch is pressed.  Lines 11 and 12 check to see if the switch has changed from it’s previous stored state, if this is true then the time when the switch was pressed is saved to the variable lastDebounceTime.  Lines 14 and 15 determine if the switches state hasn’t changed for a time equal to the variable debounceDelay, this then means that it is the current stable state of the push switch.  The stable state is assigned to the variable switchState, then lines 17 to 20 determine the if the LED connected to GPIO P1.0 is on or off.   The debounceDelay was set to 10, and the algorithm performed very well allowing fast presses of the single switch, without any issues.

The watchdog timer was used in this example as it was simple to set-up and generate an interrupt every 0.5mS.  Lines 36 to 33 show the interrupt handler, some basic statements inside the interrupt generate a 1mS count, which continuously increments.  The function Mils_Count() in lines 35 to 39, is used to obtain the current count value.  The watchdog timer is not meant to be used in this way, but it is so often disabled in many examples, yet is a resource that can be exploited.  If you were producing a production embedded system this would probably not be the case, but this adds a little extra functionality to some of the low end MSP430G devices.  The watchdog set-up shown will be used in some of the other debounce examples in this tutorial, and can easily be substituted with a standard timer.

MSP430 Single Switch Debounce WatchDog Example Code

The link below contains the zip file with the full example C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

MSP430 Single Switch Debounce WatchDog

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

MSP430 Interrupt Button Control

The second example configures the GPIO pins to trigger interrupts when a change in state is detected, which is caused by a switch being pressed.  Only the interrupt handler is shown in the code snippet below, but the entire C code can be downloaded further down the page.

There are two GPIO pins set-up to generate interrupts P1.3 and P1.7.  When a switch is pressed on either of these pins, the interrupt handler is called.  The switch case statements are used here, the port 1 interrupt flag register (P1IFG) being used as the switch.  Once the correct pin interrupt has been identified, the interrupt edge select is toggled (lines 8 and 14).  Then the corresponding LED is toggled, as shown in lines 9 and 15.  Lines 10 and 16 use a delay function which basically waits for 40mS (1MHz clock).  This produced a reasonable outcome at slow to medium rates, pressing the switch at a faster rate produced indeterminate results.  The delay function is not the best method to carry out a delay as it wastes CPU time.  This technique is also not as robust a the first algorithm, especially if the switch is pressed quickly, but it does allow a whole port of switches to be used.

MSP430 Interrupt Button Control Example Code

The link below contains the zip file with the full example C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

MSP430 Interrupt Button Control

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

  

MSP430 Multiple Switch Debounce WatchDog

The third example has two examples of switch debounce algorithms, these are split into two individual functions which can be run from the main function, simply by commenting one of them out at a a time.  The functions incorporate aspects of the previous two examples, allowing multiple switches to be debounced.  The code snippet below shows both of the functions Press_Time() and Debounce_Buttons() residing inside a while loop, which is inside the main function.

The Press_Time() function will be looked at first.

Starting with line 3, the if statement is used to ensure that the switches connected to BIT3 or BIT7 have been pressed, if not the statement is considered false.  Line 5 assigns the variable state with the AND’ed value of port 1 (P1IN) with hex value 0x88 or binary 10001000.  Line 7 assigns the current Mils_Count() value to the variable Reaction_Count.  The switch case statements are used here with the variable state being used as the switch.  If the switch on P1.7 is pressed then the case statement on line 14 will be selected.  A while loop is then entered, which waits until the current Mils_Count() minus the variable Reaction_Count is greater than the variable Button_Reaction_Delay.  This allows a tunable delay to be entered with ease, for testing a delay of 100-150mS was found to produce satisfactory results.  This method produced better results than the interrupt method, but will suffer with increased switching speed.

The second function Debounce_Buttons() is basically a copy of the first example.  The variables are just doubled up and surrounded by a if statement so the code is only executed when a switch is pressed.

This works well as per the first example but with two switches, however the code is very inefficient, due to the large number if statements that are executed each time a switch is pressed.

MSP430 Multiple Switch Debounce WatchDog Example Code

The link below contains the zip file with the full example C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

MSP430 Multiple Switch Debounce WatchDog

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

MSP430 Ganssle Switch Debounce Multiple Switches

This fourth and final example is based on sample code provided by Jack Ganssle, he has an excellent tutorial located here.  The code is based on his third example, there is also a good description of the code operation with his article.  The code snippet below shows the main body of the algorithm, I have made some modifications adding a compound bitwise AND operator, as well as adding some of his considerations regarding OR’ing the final debounced port value.

Line 6 shows a function call for rawPortData(), this function simply returns the current state of port 1 and can be seen below in the next code snippet.

The debounceSwitch() function returns the debouncedORd value, and is called in the following way.

The checkButtons() function uses switch case statements to interpret which switch or GPIO pin has changed, the nice part about this code is the debouncedORd value makes the code very intuitive.

This last example is easy to port to other microcontrollers, just by changing the code in functions checkButtons() and rawPortDate().  Needless to say this code works very well and produces excellent results with the PCB tac switches used, under fast or slow switching.

MSP430 Ganssle Switch Debounce Multiple Switches Example Code

The link below contains the zip file with the full example C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

MSP430 Ganssle Switch Debounce Multiple Switches

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

Switch Debouncing Tutorial Pt/1

 

In this switch debouncing tutorial part 1 the cause and effect of switch bounce will be explained and demonstrated, then a cost effective hardware debouncing solution will be discussed, with oscilloscope captures to demonstrate the results.  The last section of part 1 will show a simple program based on the MSP430 , this can be used to see the effects of a particular switch connected to the GPIO.  Switch deboucing tutorial part 2 of this tutorial will look at further C code debounce algorithms and their effectiveness.

All the software solutions shown will be demonstrated on the MSP430G Launchpad.  However the basic principle of operation shown in the examples, can be applied to all microcontrollers, particularly the last example which is based on some code found on Jack Ganssle tutorial, this can be easily implemented on any system using the C language.

Switch Contact Bounce

Switch contact bounce is a common issue for all mechanical switches, this includes mechanical relays.  The contact bounce occurs when the metal contacts of the switch are forced together, the property of the metals used causes the contacts to bounce apart.  How often the contacts bounce apart before finally latching shut depends on the contact type and the property of the switch.  The bouncing effect can causes multiple high frequency pulses, as opposed to a clean transition at the output.  If we take an example of a microcontroller with a switch connected to one of it’s GPIO pins, the microcontroller is able to read these high frequency pulses, misinterpreting them as legitimate presses, resulting in an undesired action.

The image below shows a basic circuit used to test switch contact bounce.

Switch Debouncing Tutorial switch circuit without debounce

With the circuit constructed on some breadboard, an oscilloscope was connected to the GPIO pin header and set to trigger when the switch was pressed, the resultant capture can be seen below.

Switch Debouncing Tutorial switch without debounce circuit poor quality switchThe oscilloscope captures shows the steady state of just over 3.3V, as the switch is pressed and released, multiple pulses are visible during this time.  The switch used for this capture was an old switch I found in a bag of spares I had, it was a small momentary touch which had a sprung button.  Many of these extra pulses would be picked up by a microcontroller, causing unexpected behaviour with your program if no debouncing was used.

The next oscilloscope capture was taken using a small PCB mounted tac switch, this was set-up in the same way as the previous test.

Switch Debouncing Tutorial switch without debounce circuit good quality

It can clearly been seen that this inexpensive PCB switch has a far superior switching action, but there is still bouncing going on, as the expanded image below shows in greater detail.

Switch Debouncing Tutorial switch without debounce circuit good quality zoomed

Hardware Solution

There are many hardware solutions to solve switch contact bounce, ranging in price from a dedicated microcontroller programmed purely to act as a debouncer, or a dedicated key encoder (MM74C923) with built in debounce, to a low end solution using just a resistor and capacitor.  This tutorial will only cover the latter option, as when combined with a suitable software algorithm, provides a cost effective solution for most small microcontroller applications.

A simple resistor capacitor switch deboucing circuit can be seen below.

Switch Debouncing Tutorial switch circuit with debounce

 

The resistor capacitor combination forms an RC circuit, which has a time constant determined by τ = R*C, therefore 47kΩ*100nF = 4.7mS.  The capacitor is considered charged after approximately 5*τ, therefore roughly 25mS.  So when the switch S2 is pressed effectively closing the switch, the voltage across the capacitor is discharged through the switch to ground.  As there is very little resistance this happens quickly, but as will be shown not instantly.  When the switch is released and becomes open, the capacitor is charged via R2 and should take approximately 25mS to charge back up to the supply voltage.  Any spikes caused by bouncing contacts are absorbed by the RC circuit, however care must be taken when selecting the values to ensure the switching action is fast enough for the project.  If the resistor or capacitor is too large the time lag may cause the system responsiveness to suffer, too small and a switch with a long bounce characteristic will still have an issue.  Capturing the switch bounce with an oscilloscope is the best way to view the problem and then take the appropriate action.  The oscilloscope capture below shows the circuit in action using the cheap PCB tac switch.

Switch Debouncing Tutorial switch with debounce

This clearly shows a huge improvement in the switching noise, the falling edge shows a clean edge, while the leading edge is curved due to C1 charging through R2.  The next image shows the falling edge of the capture on a smaller time base.

Switch Debouncing Tutorial switch with debounce falling edge

The falling edge can still be seen to show the capacitor discharge curve, this takes approximately 1uS, therefore the resistance to ground is approximately 2Ω.  The next image shows the rising edge of the capture on a smaller time base, the image clearly shows the capacitor curve levelling off around 25mS.

Switch Debouncing Tutorial switch with debounce rising edge

This circuit will work sufficiently in most situations, but it is best practice to discharge the capacitor in a more controlled fashion, especially if there are higher currents and voltages involved.  A second resistor can be used in conjunction with R2, thus ensuring C1 has a higher resistance path to ground, when the switch S2 is closed.  The image below shows a circuit using this additional resistor (R1).

Switch Debouncing Tutorial switch circuit with debounce 2nd resistor

The combination of R1 and R2 has very little impact on the original time constant, but allows a controlled discharge of the capacitor to ground.  The value of R1 would typically be less than 6.8kΩ, being dependant on the requirements of the system.  This will ultimately improve the life of the switch, as it avoids high instantaneous currents.

Before finishing part 1 of this tutorial, a basic code example is shown below which allows some of the contact bounces from a switch to be recorded on a MSP430 Launchpad.

The code snippet above is used with an external switch, connected to GPIO pin P1.0, which is configured to function with Timer0_A.  Timer0_A is set-up in capture mode and configured to trigger an interrupt on every falling edge pulse.  Every time the interrupt is triggered the variable count is incremented, therefore by running this code it is possible to determine roughly how noisy a switch is.  To see the updated count value, the code can be run then the switch pressed, the code can then be paused to check the value of Count, or a breakpoint can be set and the variable Count watched.

Test Code

The link below contains the zip file with the full example C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

MSP430 Debounce Switch Test

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

In Part 2 debounce algorithms will shown with C examples, they will all be written to run on the MSP430 but the principle of operation can be carried over to other microcontrollers.  The last code example in particular can easily be implemented on other microcontrollers.

PID Tutorial C code Example Pt/2

In this PID tutorial C code example Pt/2, the basic concept of a Boost PID controller will be explored.  All the PID controller C code is stepped through, as well as some basic concepts for testing and tuning the controller.  The final C code example can be downloaded via the link at the end of the article.

Hardware Overview

The image below shows a rough blocked out diagram of the boost circuit and feedback loop.

PID Tutorial C code Example using a Stellaris LM3S6965

As can be seen it’s a fairly simple design, with the output voltage being monitored and fed back to the LM3S6965.

A schematic for the boost converter can be seen below, this circuit was originally made to test a variable voltage boost converter.  The original design would use a 5V input which would then be boosted to either 9V, 12V or 15V, this was controlled via a state machine running on the Stellaris LM3S6965.

PID Tutorial C code Example using a Stellaris LM3S6965

The drive circuit for the mosfet uses 2 transistors in a totem pole configuration, and a 3rd transistor is to ensure a small current is sourced from the LM3S6965.  The main boost circuit itself consists of L1, Q1, D1 and C3.  The sampled output voltage via the potential divider is first passed through an operational amplifier U1A, configured as a non inverting amplifier which provides a gain of 2.2.  The operational amplifier U1B acts as a unity gain buffer, it’s input is connected to 3 resistors R7, R8 and R9.  These 3 resistors provide the offset voltage of 770mV and U1B ensures there is a high impedance input.  The output of U1B feeds the offset voltage to R4 and then to the negative input on U1A (effectively offsetting ground).  The boost converter was originally set-up to measure voltages between 4V and 19V.  So the operational amplifier arrangement with offset, ensures the sampled voltage range uses almost the full range of the ADC.  For the PID testing the output voltage will be regulated to 9V, which is equal to 353 on the ADC which is also the set point value.

Software

The software used was written after reading various sources on PID.  It has been designed so it is easy to understand, as it uses local and global variables.  A more efficient way would be to use a typedef structure or typedef struct in C.

So firstly we have our constants and global variables.

In the first part of this tutorial the proportional (Kp), integral (Ki) and derivative (Kd) constant values were mentioned.  These are the values which provide the tuning for the PID control system.  The next constant is the set point, this was observed as the read ADC value, when 9V was present on the output.  The 9V was measured and adjusted using a multimeter with a fixed load on the output, the duty cycle had a fixed value which was then increased until 9 volts was reached.  The first 2 global variables are used to store the accumulated and historic error values required for integration and differentiation.  The global variable PWM_Temp is initially given a value, then this is used to store the old duty cycle value, which is then used in the new duty cycle calculation.

The next set of variables are all local to the PID function called PWM_Duty_Change(), all the code that follows will be inside this function, until the closing brace of the function is stated and mentioned.  Additionally the entire code which was used on the LM3S6965 can be downloaded (bottom of the page), so it can be seen how and when the function was called.

The first 2 local variables are called iMax and iMin, these are used to prevent integral windup.  More will explained on integral windup further in the tutorial, but for now we will just run through the variables.  The next 4 variables have already briefly been touched upon in part 1 of this tutorial, these are Err_Value, P_Term, I_Term and D_Term.  Then we are left with new_ADC_value which is simply the latest sampled value form the ADC, and finally PWM_Duty which will be the new PWM duty cycle value passed to the timer module.

The read ADC code does not need much explanation, other than a function was created to read the ADC and return the value as an integer.  If you are using this code on another microcontroller, you simply need to construct an ADC read function, then insert instead of the read_ADC().

Going back to part 1 of this tutorial it was shown that the error value can be obtained, by simply taking the newest error value away from the set point, that’s all this line performs.

To obtain the proportional term the Kp constant is multiplied by the error value.

The accumulated error value is used in integration to calculate the average error, so first the current error value must be added to the accumulated value, and that’s what this line performs.

The if and else if statements are used to cap the accumulated integral term, by simply setting upper and lower thresholds.

The integral term is then calculated by multiplying the Ki constant with the accumulated integral value.

The first line of this code snippet calculates the derivative term.  To understand how the code works the second line needs to be run through quickly, this basically assigns the newest ADC value to the d_temp global variable.  So the d_Temp variable effectively stores the historic error value, therefore allowing the derivative to be calculated.  Now looking at the first line again, the newest ADC value is taken away from the historic value, the difference between the 2 would allow the rate of change to be calculated (assuming the time between the readings is a known quantity). Then this value is multiplied by the derivative constant and assigned to the derivative term.

Now that we have all the PID terms calculated, they can be used to change the PWM duty cycle.  This next piece of code adds all the PID terms together, then they are subtracted from the PWM_Temp variable (PWM_Temp usage is shown shortly as it comes towards the end of the function).  This value is then assigned to the PWM_Duty variable.  The way the PID terms are used here is specific to this program, firstly the sum of the PID terms is subtracted, this is due to the final electronic circuit used.  What’s important here is the PID terms are summed, then they need to be used in such away as to construct a valid PWM duty cycle or other chosen control method.

The if and else if statements are used to prevent the duty cycle from going too high or too low, in this case this simply prevents the output voltage from going too high or too low.  If say you were using a half bridge driver integrated circuit, these usually state a maximum duty cycle of say 99%, if this is exceeded the voltage doubler cannot function correctly, so having limits can be a good protection system.

This line is again limited to this specific application, it simply calls the function adjust_PWM(), which has the new PID calculated duty cycle value, as a parameter.

The final statement in the function before the closing brace, assigns the current PWM duty cycle value to the PWM_Temp global variable.

Integral windup can occur if the integral term accumulates a significant error, during the rise time to the set point.  This would cause the output to overshoot the set point, with potentially disastrous results, it can also cause additional lag in the system.  The integral windup prevention used in this example, places a cap on the maximum and minimum value the integrated error can be.  This effectively sets a safe working value and is considered good working practice in any PID system.  The values used for integral windup as with the PID constant gain values are specific to this system, these would need to be determined and tuned to your system.

Step Response

The intention was to also explore the well documented Ziegler-Nichols approach, however time constraints for the project did not allow this method to be fully explored.  Some basic concepts of how to carry out a step response test will be shown, as I am sure it will prove useful.

The systems step response shows how the system responds to a sudden change, electronic circuits switch quickly, so an oscilloscope was the best piece of equipment for the job.  The boost converter was set up with a fixed load, a fixed PWM duty cycle and no feedback , therefore in an open loop configuration.  Then some additional test code was added, initiating these 2 extra functions when a button was pressed on the LM3S6965 development board :

  1. A free GPIO pin would be taken from low to high
  2. The PWM duty cycle would decrease by 10% effectively increasing the output voltage

The free GPIO pin would be connected to channel 2 on the oscilloscope, and in this way can be used as a trigger to start a capture event.  Channel 1 on the oscilloscope would be connected to the output of the boost converter, thereby capturing the step response as the output voltage rises.  The image below is a photograph of the captured step response on the oscilloscope.

PID Tutorial C code Example using a Stellaris LM3S6965

The GPIO pin was polled before the PWM duty cycle was updated, however this happens so quickly, it is difficult to distinguish this.  The lower square wave type step is the GPIO pin on channel 2, and the top curved step response is the output from the boost converter.  It can be seen to overshoot it’s settling level at the beginning then oscillate for a time before settling down, this oscilloscopes accuracy wasn’t the best, using a longer time base did not show any extra detail on the oscillations.

If the step response was of a first order, a calculation based on the reaction curve could be performed.  However the step response from the boost circuit is of a second order, and has an under-damped nature.  In order to explore this calculation further, requires another tutorial altogether, however further reading on this can be found here.

The step response of a similar system under the control of a PID controller can also be viewed.  This can be achieved by using a similar set up, the external pin is used again to trigger an oscilloscope capture.  That same GPIO pin is also used to switch a mosfet, which places an additional load in parallel with the output of the boost converter.  The PID algorithm will then regulate the output voltage to ensure it meets the set point with the new load, and the step response can then be captured.

Testing and Tuning

The system was set up and a basic tuning approach was used, the image below shows the system on the test bench.

PID Tutorial C code Example using a Stellaris LM3S6965

The image shows the following pieces of equipment:

  • Hewlett Packard multimeter connected to the output, monitoring the output voltage
  • Bench power supply, supplying 5V to the circuit
  • Oscilloscope, used to monitor the PWM duty cycle
  • 0-100Ω bench potentiometer
  • Boost converter PCB, LM3S6965 development board and a laptop to tweak the code

With everything connected the PID algorithm was set up, but with only the proportional part in operation.  The set point was set to 353 as mentioned previously, which produced close to 9V give or take 10-15mV.  The load was fixed and set to 100Ω.  Initially the proportional gain constant Kp was set very low around 0.001, this was too low so it was increased over a few steps until 0.01.  At this point the output voltage was observed to be approximately 7.5V, and the duty cycle waveform was observed to have a small amount of jitter, as the duty cycle fluctuated +/- 0.5%.  The Kp value was again increased, until the output voltage read approximately 8V, the duty cycle was again observed and found to be fluctuating by a greater amount, by approximately +/-5%.  The increase in jitter on the PWM duty cycle can be equated to greater oscillations on the output voltage, the multimeter was not suitable for observing these.  It would have been possible to see them on the oscilloscope but this probably would have involved a stop capture then restart method, therefore to make the process quicker the PWM duty cycle was considered ‘good enough’.

At this point the Kp value was backed off, to the previous level of 0.01 so the output voltage was at 7.5V.  This point can be considered close to the offset level mentioned in part 1 of this tutorial, and for ease of reading the image showing the offset level can again be seen below. This image also illustrates again how too larger Kp value can introduce instability in the output.

PID Tutorial C code Example using a Stellaris LM3S6965

Now with this level reached, the integral part of the algorithm was introduced.  All the hardware was untouched, just a simple modification to the algorithm was made.  The initial value chosen for Ki was 0.01.  This was then loaded on to the LM3S6965 and the output voltage on the multimeter was immediately observed to read 9.02V, +/-10mV.  The oscilloscope was also observed to have minor jitter as before of only a few half percent.  The integral value was not tweaked any further, but in most cases tuning the Kp and Ki values would take a greater time and under a wide range of conditions.

With the PI controller working on a basic level, the next test was to see how it performed under different load conditions.  First the bench potentiometer was left at 100Ω and the input current and output voltage were noted, the wiper was then moved to the middle (approximately 50Ω) and again the output voltage and input current were noted.  At 100Ω the output voltage was 9.02V with a current of 180mA, at 50Ω the output voltage was 8.99V with a current of 500mA, both output voltages still showed minor voltage variations in the +/-10mV range.

The next step was to move the potentiometer wiper rapidly between the 100Ω and 50Ω position, then observe the output voltage and duty cycle (not the most scientific test, but goes some way to demonstrating the system).  With this test being performed the duty cycle was observed to rapidly increase and decrease, too quick to observe anything further and a step response would be the best method to use here.  The output voltage was observed to have a minor variations, fluctuating +/-15-20mV

After this test, the derivative constant was introduced and tweaked to find the best settings. The Kd constant was not observed to have a huge affect on the system, unless increased dramatically which produced instability.  This set up is not ideal for testing the derivative term and a more detailed and longer term approach would be best.

The basic test performed seemed to conclude the PI controller was working as per the research carried out.  The system used here updates at a very fast rate, therefore observing the step response at this point would be best practice.  As this system has no critical importance other than to explore PID, it simply wasn’t necessary to tune it to a high degree of accuracy.  I have a number of projects in the works however, which touch on this subject again and I intend to post them when I have time.

Example Code

The link below contains the zip file with the complete C code and an external functions folder, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

PID LM3S6965 C code

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

PID Tutorial C code Example Pt/1

In this PID tutorial C code example Pt/1, the basic concept of a PID controller will be explored. The full example code is implemented on a Stellaris LM3S6965 microcontroller, and is used to control a simple boost converter circuit, regulating the voltage with a change in load resistance. The boost circuit is not covered in-depth in this tutorial, but the fundamentals of a boost circuit are covered.

In this first part the basic concepts of a control system will be explored, as well as the PID controller.  The second parts covers the code implementation in the C language on the Stellaris LM3S6965, all the code is stepped through and can be downloaded at the end of the second part.

Basic Control System Concepts

To understand how PID controllers are used, it is important to first understand some basic control system principles.  The image below illustrates the 2 basic types of control system.

PID Tutorial C code Example using a Stellaris LM3S6965

The open loop system can clearly be seen to have no feedback, therefore if the load changes on the motor, the motor speed will change.  The control unit cannot command the driver to increase or decrease the power to the motor, as it has no knowledge of the speed change induced in the motor, by the change in load.

The closed loop system however has feedback from the motor.  So if the motors speed were to decrease due to an increase in load, the control unit could command the driver to increase the power to the motor, keeping a constant speed.  Common direct current motor control is achieved via PWM, and simply increasing or decreasing the duty cycle will increase or decrease the motor speed.

On/Off Controller

Using the above closed control loop as an example, the basic operation can be broken down. The feedback signal will often go through some signal conditioning circuitry, before being fed to the control unit.  The control unit will have some reference set point or threshold levels, that it is aiming to keep the motor speed at or between.  If a reference set point is used the new feedback signal could be used to generate an error value in the following way

Error_Value = Set_Point – New_Feedback_Value

We will come back to the Error_Value shortly as this is used in the PID controller, but first lets look at a more simplistic approach using the threshold level.

If threshold levels are used, lets say to keep the motor speed between 1200-1300rpm, the feedback signal could be directly used as a comparison.  Therefore if the feedback signal is 1320rpm the control unit needs to decrease the motor speed.  If we now said the control unit was a microcontroller, and the driver was a simple amplifier.  The microcontroller could reduce the duty cycle of the PWM, this in turn would then slow the motor down.  If we consider the motor to have a very quick response to changes in PWM drive, and the load on the motor to alter subtle over time, then there are 2 important factors to consider.  (1) The speed at which the PWM duty cycle is updated by the microcontroller, and (2) how large a change is made to the duty cycle on each update i.e. 1%, 5% etc.  This control system is often known as an on/off controller, the 2 factors can be tuned to suit the individual control system.  An example of on/off controller which is slightly more complex than this example, as it has other parameters is a Perturb and Observe algorithm used in a solar MPPT for photovoltaics.  The image below shows how an on/off controller usually oscillates around the set output level.

PID Tutorial C code Example using a Stellaris LM3S6965

On/off control systems typically oscillate around the desired output level, as they overshoot and undershoot the desired value.  The threshold level example used has no fixed setpoint so even if the motor speed stayed within these bounds, its speed would still oscillate to some degree.  The size of these oscillations is dependant on the PWM step size and the control loop speed.  If the system is very dynamic and changing at a fast rate, then a compromise between these 2 factors needs to be reached, to ensure good tracking performance.  When the desired reference value is reached, the size of the oscillations will be dependant on the PWM step size.

PID Controller

PID stands for Proportional, Integral and Derivative.  PID controllers have been used since the 1890s, and were originally developed by Elmer Sperry for an automatic ship steering system.  A PID control system uses 3 gain constants, which are multiplied with the Error_Value.  The proportional value gain constant is referred to as Kp, the integral value gain constant as Ki and the derivative value gain constant as Kd.   The results of these multiplications produces 3 further values, for this tutorial these are referred to as the P_term, I_term and D_term.

As previously mentioned the Error_Value can be obtained from simply taking the New_Feedback_Value away from the Set_Point.  In a PID controller the error value can simply be multiplied with the Kp constant, but for the Ki and Kd constants a different approach is required.  In order to calculate the I_term and D_term historic error values are required.  The I_term is using integration which gives the average error value over time, and the D_term is using differentiation which gives the rate of change of the error value over time.  Once all the PID terms are calculated, these new values are then summed together and used in the final control output.

The P, I and D terms have different affects on the final system performance, and need to be tuned to the individual control system.  The ultimate aim for any control system is to respond as quickly as possible, without excessive overshoot and oscillations around the set point.  The system response ideally needs to reach a settled state as quickly as possible, the settled state is very subjective and dependant on the application.  A block diagram of a PID control system can be seen below.

PID Tutorial C code Example using a Stellaris LM3S6965

The proportional term (P_term) provides an output value which is proportional to the current error value.  The Kp constant value determines how large the gain response will be to the current error value.  A high proportional gain constant will induce a large change in the output, often overshooting the set point level.  If the gain is too high the system can become unstable and excessive oscillations can occur.  Another affect of a high Kp constant is faster response time, vice versa a low Kp constant will result in a slower response time.  When a low Kp constant is used, there will still be oscillations and some overshoot of the set point depending on the level, however these will not be as aggressive.

A low Kp value will also settle in an offset position slightly below the set point level, this offset position can be used when tuning a PID system.  The image below illustrates the step response waveforms of a system with high and low Kp gain constants, on a hypothetical control system.

PID Tutorial C code Example using a Stellaris LM3S6965

 

The integral term (I_term) is used to bring long term precision to the control loop.  It is proportional to both the magnitude and duration of the error.  Using Integration allows for the average error to be calculated, as the sum of the instantaneous error over time provides an accumulated offset.  The accumulated error is then multiplied by the Ki gain constant, allowing the offset which should have been corrected previously, to be added to the controller output.  This then accelerates the controller output response towards the set point, eliminating the offset found when just using a proportional control value.

As with the the Kp gain constant the Ki constant, needs to be tuned.  If the Ki value is too high the system will have a faster response time, but it will also be likely to overshoot the set point, inducing further unwanted oscillations before finally settling.  An ideal Ki value produces a response time that is fast enough for the application, with little or no overshoot and a quick settling time.  The image below illustrates the step response waveforms with a tuned Kp value already set, then a few Ki gain constants are applied on a hypothetical control system.

PID Tutorial C code Example using a Stellaris LM3S6965

 

The derivative term (D_term) is the least used of the three terms, most controllers are based on PI control algorithms.  Introducing the Kd term is generally used in specific control systems, these are usually where overshooting the set point can cause dangerous results. Differentiation is used to determine the rate of change, by using the instantaneous error value and the previous error value, so a rate of change can be determined.  The derivative term can be used to predict system behaviour, improving settling time.

PID Control Loop Tuning

As can be seen the constant gain values Kp, Ki and Kd all affect the control system in different ways, therefore careful tuning of these values is an essential part of an effective PID controller.  Tuning a PID system is a difficult problem, there are only 3 parameters but finding a balance often takes some time depending on the complexity of the system.  Some systems have auto tuning features, but in some situations to have the best performance from a system, it is often recommended to manually tune.

A well known tuning method is called Ziegler-Nichols, developed by John G. Ziegler and Nathaniel B. Nichols.  This relies on the Ki and Kd gain constants first being set to zero.  The the Kp constant is adjusted until it reaches the ultimate gain, which is classified by the output from the control loop oscillating at a constant amplitude.  Then the ultimate gain value and oscillation period are used to calculate the Ki and Kd constants.  More about the Zieglar-Nichols method can be found here.

There are other methods and simply searching on Google will yield many results.

The C code, set-up and tuning of the boost converter will be covered in part 2 of this tutorial.

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

Stellaris Timer Example

In this Stellaris timer example two timers are used to code a basic frequency counter.

The code process is quite simple to implement, and as mentioned previously with other stellaris examples I would recommend using the StellarisWare Peripheral Driver Library PDF as a reference, which can be found here.

The first timer is configured to count the leading edge of the incoming square wave, the second timer is used to count for a fixed time and then generate an interrupt. Then a simple calculation is performed using the second fixed timer value, and the accumulated leading edges counted. The positive going edge count is then stored, and also reset every time the second timers interrupt is generated.  The image below outlines the basic operation of the example that will be shown.

Stellaris Timer Example Code frequency counter LM3S6965

 

As can be seen from the image timer 2 was chosen to generate an interrupt every 100mS, this was deemed as an adequate time to refresh the count, and can easily be increased or decreased pending on the application.  The stellaris LM3S clock frequency is running at 8MHz. Each clock pulse period can be calculated by taking the reciprocal of 8MHz (1/8MHz) which is 125nS, then dividing 100mS by 125nS we reach a value of 800,000.  The 800,000 is not used directly in this code, as the clock is simply divided by a constant, but this illustrates how the value was reached.

A signal generator was used to feed a square wave into the stellaris, this was then varied and the results of the stellaris code displayed on the on-board OLED.  A video of the frequency counter in action can be seen below.

So now lets dive into the code.  As mentioned before the system clock was running at 8MHz, using the on-board crystal, the code snippet below is used to configure the clock and also some OLED initialisation.

Then both of the timer peripherals need to be enabled.

In the code example Timer0 is used to generate an interrupt every 100mS, and Timer1 is used to measure the leading edge pulses from the signal generator.  Therefore a GPIO input needs to be setup and assigned to function with Timer1, the next section of code performs this.

An interrupt needs to be enabled and set-up for Timer0A.

Then the 2 timers need to be configured.  The first 2 lines of code set-up Timer0 as a full width periodic timer, and Timer1 as a half-width edge count capture.  Then Timer0 (TimerA) is loaded with the 100mS count period, and Timer1 is loaded with a value of 10000.  Timer1 is loaded with a value as it counts down for every positive going edge.  This timer example could effectively count upto 2MHz (a quarter of the 8MHz clock frequency), it was tested successfully with higher frequencies, to do so the value preloaded into Timer1 needs to be increased.  The final line in this snippet, sets Timer1 (TimerA) to trigger on positive going edges.

Finally the timers need to be enabled.

Now that the timers are configured and enabled the code for the interrupt handler for Timer0 can be configured.  This basically clears the interrupt, stores the value counted by Timer1 and then resets Timer1.

This is not necessarily the best way to do this, but it performed the task required of the test at the time.  As has been mentioned the code displays the frequency value on the OLED, to do this an itoa function is used to change an integer into a char and then print to the display, all this takes quite a few processor cycles, and in this way has been removed from delaying the interrupt handler.

The final code block shows the function used to calculate the timer frequency.  It could be improved upon using a modulus to display the frequency in kHz, and printing a decimal point in the appropriate place, this would allow displaying a greater range of frequencies with more ease.

The following image shows a screen capture from the YouTube video, which demonstrates the program works within a reasonable accuracy.

Stellaris Timer Example Code frequency counter LM3S6965

Example Code

The link below contains the zip file with the complete C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

Frequency Counter

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

Stellaris DAC7571 Tutorial

The Stellaris DAC7571 tutorial will show how a LM3S6965 evaluation board is interfaced to the DAC7571 using the I2C bus.

DAC7571 Hardware

The DAC7571 is manufactured by Texas Instruments, and has the following key features which make it ideal for experimenting with:

  • 6 pins IC in a SOT23 package
  • 12 bit buffered voltage output, therefore the DAC has a range of 2 to the power of 12 = 4096
  • I2C interface
  • Supply voltage from +2.7V to +5.5V

The DAC comes in an SMT package, TI supply SMT prototyping boards which allow the DAC to then give the footprint of a standard 8pin DIP package.  This method is useful as it allows the DAC to be used in various other projects and easily reused. The image below shows the completed prototyping board, fitted to small veroboard used for testing the I2C bus. Stellaris DAC7571 Tutorial using the LM3S6965 evaluation PCB

DAC7571 I2C

This is not a tutorial on I2C but it is necessary to give a brief decsription of the protocal, as these leads into explaining how to communicate with the DAC7571 correctly.  The datasheet for the DAC7571 can be downloaded from here I2C is a 2 wire protocol using a data wire (SDA) and a clock wire (SCL).  There is a Master device which initiates contact with up to 127 Slave devices on a single bus, each slave has an individual 7 bit address.  There can be more than one Master on a bus, but this is beyond the scope of this project, so will not be covered here.  For this project the master will be the LM3S6965 and the DAC is the slave (the DAC can only be a slave).  There is a certain sequence of events for any data bus, which is covered briefly in the next few lines.

  1. The SDA and SCL lines when in idle state naturally sit high or logic level 1.  The master initiates contact on the bus by pulling the SDA line low, when the SCL line is still high, this indicates to any slaves on the bus serial data transfer has started.
  2. After this the master generates the serial clock on the SCL line.
  3. The master then sends out an address byte of the slave it wants to communicate with.
  4. After sending out the address byte the master generates a ninth SCL pulse, then monitors the SDA line during the high period of this ninth clock cycle.
  5. The SDA line should now be pulled low by the receiving slave during the high period of the ninth clock cycle, this is an acknowledge signal and lets the master know the address sent successfully matches a slave on the bus. Further data bytes can be sent to or read from a slave by the master, using the a similar method to the steps explained.

The I2C protocol has fairly strict timing requirements, so it’s important to note while the bit stream is generated, the master ensures the timing for valid data.

The DAC7571 datasheet contains a great deal of information about interfacing, and all the necessary information regarding the I2C interface can be found on page 13 to 18. It is only possible to have 2 of the DAC7571 devices on one I2C bus, this is due to the way the slave address is set on the DAC. Pin 6 is called A0, pending how this pin is connected determines the address of the DAC, if the pin is connected to Gnd the slave address is 1001100 (0x4C), if A0 is connected to Vcc then the slave address will be 1001110 (0x4E).  A0 for this project was connected to Gnd. Now that the address is taken care of, it was necessary to understand how to send data to the DAC.  The image below is taken from page 17 of the datasheet. Stellaris DAC7571 Tutorial using the LM3S6965 evaluation PCB From the table it can be seen that 2 bytes of data need to be sent to the DAC, so this is effectively makes up 16 bits.  The first 4 bits are used for control data, the remaining 12 bits are used to set the DAC value, hence it’s a 12 bit DAC.  The first byte starts with two zeros then contains two control data bits, the last 4 bits of the first byte contain the first 4 bits of a 12 bit word. The second byte contains the last 8 bits of the 12 bit word.  The image below demonstrates how the data is broken up. Stellaris DAC7571 Tutorial using the LM3S6965 evaluation PCB

Software

The Stellaris has a library specifically written for the I2C protocol contained within the TI software bundle StellarisWare, this makes interfacing with devices which support I2C and many other protocals much easier, compared to lower end microcontrollers like the MSP430G series.  An essential read is the Stellaris Peripheral Driver Library in PDF format, which can be downloaded from here. There are sections dedicated to all the driver libraries, this document was referenced heavily for this project.  In order to use I2C on the Stellaris, the peripheral must be enabled (there are two I2C ports on the Stellaris I2C0 and I2C1). Then the port the peripheral is on must also be enabled, followed by the individual pins on that port. The following functions below carry out the port enabling.

Once the ports have been enabled the I2C needs to be initialised, via the following function which also sets the speed of the bus (false indicates 100kHZ).

After this the microcontroller can begin it’s duty as master, the code below can be used to test the DAC.  Further code was written using a function with all the code below placed inside, then the function was simply passed parameter values to set the DAC output voltage.

The DAC supply voltage is 3.3V, therefore 3.3V/4096 = 806μV per step, so a value of 1532 for example should be as follows 1532*806μV = 1.235V When the above code was written into a test program, 1.24V was observed on the multimeter.  The Hex values of 0x05 as the first byte and 0xFC on the second byte equate to a 12 bit binary value of 010111111100, which is equal to 1532 in decimal.

Example Code

The link below contains the zip file with the complete C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website Stellaris DAC7571 I2C C code

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.