MSP430 Programming Tutorial Pt/2

 

In this second part of the MSP430 programming tutorial examples of GPIO register settings will be shown and explained.  Additionally register examples for some of the internal peripherals will be demonstrated and explained.  The first part of the tutorial can be found here.

Changing the GPIO Registers to your desired configuration

The following examples should help to illustrate how you change the individual bits, as well as multiple bits in the GPIO registers to achieve exactly what you want.  There is a reference to BIT3 and BIT7 being defined as hexadecimal values, these values can be found in the msp430g2253.h header file inside Code Composer Studio, or the MSP430 software provided by Texas Instruments.

MSP430 Programming Tutorial GPIO register statements 1

So by using this statement we only change BIT7 of port 1 to a logic 1 or GPIO P1.7. This is very powerful as it allows individual pins to be configured, without effecting other pins on the same port.  But what if you want to adjust multiple pins to outputs, well that can be achieved quite easily, two ways are illustrated below.

MSP430 Programming Tutorial GPIO register statements 2

So turning a single registry bit or multiple bits to a logic 1 are covered, how about assigning a logic 0 to a single register bit or multiple register bits.  The following images will demonstrate how this is achieved.

MSP430 Programming Tutorial GPIO register statements 3

And for multiple bits.

MSP430 Programming Tutorial GPIO register statements 4

There is one more operator that is commonly used on GPIO pin register bits, that is the ^ or XOR bitwise operator.  This is used in many examples on the internet to toggle the LED’s on the launchpad, the example below demonstrates it’s use.

MSP430 Programming Tutorial GPIO register statements 5

Although all these examples are only used with the P1OUT register, the same principles can be applied to all the GPIO port registers.  The examples shown where multiple registers are written to, using a combined hex value will also optimise any code, saving execution time by removing additional arithmetic in the form of an addition.

  

Understanding and Changing Peripheral Registers

Understanding how to change bits inside the peripheral registers, is not a great leap in understanding from the GPIO ports.  A few examples will be shown which are based on the ADC peripheral.  The ADC10 Control Register 1 (ADC10CTL1) will be used as the example register, but all registers will follow the same principle.  The image below is extracted from the MSP430 family guide and shows the ADC10CTL1 register.

MSP430 Programming Tutorial ADC10CTL1 Control Register 1

So what we can see here is the register is a 16 bit register and the bits are split into blocks which correspond to different parameters.  I have covered what these individual blocks do in a previous tutorial dedicated to the MSP430 ADC, found here.  It can be seen that the blocks correspond to certain bits inside the register, for example INCHx occupies Bits 12-15 of the register and ADC10DIVx occupies Bits 5-7 of the register.  To illustrate this we could view the 16 bit register in binary form:

INCHx occupies the bits shown in bold 0000 0000 0000 0000
ADC10DIVx occupies the bits shown in bold 0000 0000 0000 0000

As with the GPIO port pins Texas Instruments have provided defines in the header files, so it is not necessary to remember the binary or hexadecimal values for the register settings. The names used for these register settings are shown above i.e. INCHx and ADC10DIVx.  As INCHx occupies four Bits it therefore has 16 possible combinations and ADC10DIVx has 8, hence the small x after each name.

The next two images are again extracted from the MSP430 family guide and show how the bit combinations correspond to different parameters.

MSP430 Programming Tutorial ADC10CTL1 Control Register 1 INCHx

MSP430 Programming Tutorial ADC10CTL1 Control Register 1 ADC10DIVx

So now lets look at a command to set the ADC10CTL1 register using the parameters INCHx and ADC10DIVx.

The code snippet above basically adds the two parameters together and assigns them to the register using a compound OR assignment operator.  Now lets look at this in binary form, which will help shed some light on the process.

MSP430 Programming Tutorial ADC10CTL1 INCHx + ADC10DIVxSo by using this command the register parameters can be set individually, or multiple parameters can be set in one go.  As with the GPIO port settings a hexadecimal value can be used to set the parameters as well.

The code snippet above achieves the same result as well as being more efficient, however the code becomes much more obfuscated.

That covers setting the register bits to 1, how about setting the register bits to 0.  This is achieved in the same way as with the GPIO, the image below illustrates the operation.

MSP430 Programming Tutorial ADC10CTL1 ~INCHx

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 Programming Tutorial Pt/1

 

In this MSP430 programming tutorial part 1 some of basic C operators used for programming the MSP430 will be looked at.  The GPIO port registers will then be looked at in greater detail.  In part 2 example code for the GPIO registers will be shown and explained, as well as examples for the the ADC peripheral register.   The MSP430G2253 Launchpad will be used as the reference microcontroller, the primary IDE used is Code Composer Studio (CCS). The MSP430G series family guide, as well as other useful information can be downloaded directly from Texas Instruments webpage here.

C Language Bitwise Operators

If you are familiar with Bitwise operators, skip this section and and start with the MSP430 GPIO ports section further down this page.

Some basic C language bitwise operators will be looked at first, then how these apply to GPIO ports will be demonstrated.  The C language has 8 types of operators and bitwise operators are 1 of these.  The bitwise operators are fairly easy to understand and if you have ever looked at logic gates and truth tables, then some of these will be immediately recognisable. For the following examples two variables will be used a and b, they will also be assigned values; Decimal: = 48 and b = 24, Binary: a = 0011 0000 and b = 0001 1000.

Bitwise Operator &

a 0011 0000
b 0001 1000
a&b 0001 0000

The binary AND operator copies a bit or logic 1 to the result, only if a logic 1 exits in both operands.  So the result of a&b = 0001 0000 or 16 in decimal.

Bitwise Operator |

a 0011 0000
b 0001 1000
a|b 0011 1000

The binary OR operator copies a bit or logic 1 to the result, if it exists in either operand.  So the result of a|b = 0011 1000 or 56 in decimal.

Bitwise Operator ^

a 0011 0000
b 0001 1000
a^b 0010 1000

The binary XOR operator copies a bit or logic 1 to the result, if it exists in one operand as a logic 1, but not both.  So the result of a^b = 0010 1000 or 40 in decimal.

Bitwise Operator ~

a 0011 0000
~a 1100 1111

The binary NOT operator effectively flips the bits, so 1’s become 0s and vice versa.  So the result of ~a = 1100 1111 or -48 in decimal (signed variable) or 207 in decimal (unsigned variable).

Bitwise Operator <<

a 0011 0000
a = a<<2 1100 0000

The binary LEFT SHIFT operator moves the operands bits left, by the number of bits specified, which is this case is 2.  So the result of aa<<2 = 1100 0000 or 192 in decimal.  This also effectively multiplies the value of a by a factor of 4.

Bitwise Operator >>

a 0011 0000
a = a>>2 0000 1100

The binary RIGHT SHIFT operator moves the operands bits right, by the number of bits specified, which is this case is 2.  So the result of a = a>>2 = 0000 1100 or 12 in decimal. This also effectively divides the value of a by a factor of 4.

  

MSP430 GPIO Ports

Looking at the 20 pin MSP430G2253 supplied with the Launchpad, it has two GPIO ports. Both ports have 8 GPIO pins numbered as follows, port 1 pins P1.0 to P1.7 and port 2 pins P2.0 to P2.7.  The image below is extracted from the MSP430G2253 datasheet.

MSP430 Programming Tutorial MSP430G2253 20 pin GPIO layout

All the individual GPIO pins can be configured to connect to internal peripherals, for example, providing a connection for the ADC to an external source, or providing the output from Timer module in the shape of a PWM signal.  The GPIO’s as the acronym tells also provide General Purpose Input and Output operations.  Not all of the GPIO pins can be configured to be used by all the internal peripherals, a detailed list of how the pins can configured can be found in the datasheet for that particular microcontroller.  The image below again shows an extract from the MSP430G2253 datasheet, illustrating the GPIO pins P1.0 and P1.1 and their individual associated peripheral functions.

MSP430 Programming Tutorial MSP430G2253 GPIO Functions

Defining how each of the eight GPIO pins are configured for each port, is achieved by individual registers.

PxIN Input Register

The PxIN register reflects the value of the signal being input into the GPIO pin, when configured as an I/O function.  So by reading this value you can determine if there is a logic 0 or a logic 1 on the input.  Bit = 0: The input is low, Bit = 1: The input is high.  A statement using this function for GPIO port 2 and pin P2.4, could look like this if ((P2IN & Bit4) == BIT4);.

PxOUT Output Register

The PxOUT register determines the value output to the GPIO pin, when the pin is configured as an I/O function.  The PxOUT register works in conjunction with the PxREN as follows:

Pullup/pulldown resistor disabled: Bit = 0: The output is low, Bit = 1: The output is high.

Pullup/pulldown resistor enabled: Bit = 0: The pin is pulled down, Bit = 1: The pin is pulled up.

A statement using this function for GPIO port 1 and pin P1.4, could look like this P1OUT &= ~BIT4.

PxREN Pullup/Pulldown Resistor Register

The PxREN register enables or disables the internal pullup/pulldown resistor, which corresponds to the individual I/O pin.  Bit = 0: Pullup/pulldown resistor disabled, Bit = 1: Pullup/pulldown resistor enabled.  A statement using this function for GPIO port 1 and pin P1.5, could look like this P1REN |= BIT5.

PxDIR Direction Register

The PxDIR register selects the direction of the I/O pin, whether it will be an input or an output.  This is regardless of the selected function of the pin.  Bit = 0: The port pin is switched to input direction, Bit = 1: The port pin is switched to output direction.    A statement using this function for GPIO port 1 and pin P1.3, could look like this P1DIR |= BIT3.

PxSEL and PxSEL2 Function Select Registers

The PxSEL and PxSEL2 registers allow the individual GPIO pins to be associated with the internal peripheral module functions, or simply left as standard I/O ports.  The image below was extracted from the MSP430 family guide.

MSP430 Programming Tutorial PxSEL and PXSEL2 multiplex functions

A statement using this function for GPIO port 2 and pin P2.1, could look like this P2SEL |= BIT1;.  When using these registers, it is important to consult the datasheet and pin schematics, for the specific device.

P1IFG, P2IFG Interrupt Flag Registers

Only GPIO ports 1 and 2 have interrupt functionality.  The P1IFG and P2IFG registers hold the interrupt flag for the corresponding I/O pin, the interrupt flag is set when the selected input signal edge occurs at the pin.  Bit = 0: No interrupt is pending, Bit = 1: An interrupt is pending.  A statement using this function for GPIO port 1 and pin P1.1, could look like this P1IFG &= ~BIT1;.

P1IES, P2IES Interrupt Edge Select Registers

The P1IES and P2IES registers allow the interrupt edge type to be selected for each I/O pin. Bit = 0: The PxIFGx flag is set with a low to high transition, Bit = 1: The PxIFGx flag is set with a high to low transition.  A statement using this function for GPIO port 1 and pin P1.1, could look like this P1IES &= ~BIT1;.

P1IE, P2IE Interrupt Enable Registers

The P1IE and P2IE register bit enables the associated PxIFG interrupt flag.  Bit = 0: The interrupt flag is disabled, Bit = 1: The interrupt flag is enabled.  A statement using this function for GPIO port 1 and pin P1.1, could look like this P1IE |= BIT1;.

Texas Instruments also recommends configuring unused pins as I/O function, output direction, and left unconnected to prevent a floating input and reduce power consumption.

So how to change the GPIO Registers to what you want, well part 2 of this tutorial will make the GPIO settings clear and hopefully easy.  Additionally an ADC register will be explained and demonstrated.

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 Timer PWM Tutorial

 

In this MSP430 timer PWM tutorial the basic workings of the on board timer peripheral will be explained, along with some C code examples which can be downloadable at the end of the tutorial.  Additionally the video below demonstrates the examples ‘A picture paints a thousand words, a video displays a thousand pictures’.

The MSP430G2253 will be used as it has two timers opposed to the MSP430G2231 which only has one timer, this will allow for different examples to be shown.  All the code in the MSP430 timer tutorial is written in Code Composer Studio (CCS) v5.5.  As the tutorial will be using the MSP430G2253 as the test microcontroller, downloading the datasheet for this maybe of use and can be found here.

Before reading further if you are having trouble understanding how the registers work, and how the C code updates the individual register settings?  It would be worth reading my MSP430 Programming Tutorial, Part 1 covers the basics and Part 2 gives clear examples.  You can find them here Part 1 and Part 2.

The MSP430G2253 has two 16 bit timers, Timer0 and Timer1 both are Timer_A variants with three capture/compare registers.  The MSP430 family guide lists two types of 16 bit timer, Timer_A and Timer_B.  For the most part they are very similar except Timer_A has up to three capture/compare registers, were as Timer_B has up to seven.  The MSP430G2253 also has a watchdog timer which can be used detect system malfunctions, but will not be covered in this tutorial. The feature list for Timer_A is shown below:

  • Asynchronous 16 bit timer/counter with four operating modes
  • Selectable configurable clock source
  • Up to three configurable counter/compare registers
  • Configurable as outputs for PWM
  • Asynchronous input and output latching
  • Interrupt vector register for fast decoding of all Timer_A interrupts

Asynchronous 16 Bit Timer

The 16 bit timer increments or decrements a value from the Timer_A register (TAR), every rising edge of the clock pulse.  The TAR value can be read or written with software, and an interrupt can be enabled to generate when it overflows.  If the timer is run asynchronous to the CPU clock, any reading from the TAR should occur while the timer is not running, as the result is likely to be unpredictable.

The four modes of operation for the timer are:

Stop – The timer is stopped

Up – The timer counts from zero to the value of TACCR0

Continuous – The timer counts from zero to 0FFFFh

Up/Down – The timer repeatedly counts from zero up to the value of TACCRO (+1) and then back down to zero.

Configurable Clock Source

The clock source for the timer can be from ACLK, SMCLK or from an external source via TACLK or INCLK (Device specific).  The clock source selected can be then divided by 1, 2, 4 or 8.

Counter Compare Registers

The capture/compare blocks inside Timer_A are all identical.  Any of the TACCRx blocks may be used to capture timer data or generate intervals.  When in capture mode the Capture Compare inputs CCIxA and CCIxB, can be connected to external pins or internal signals. They can be configured to capture on a rising, falling or both edges.  The compare mode is used to generate PWM output signals, or interrupts at specific time intervals.  Each capture/compare block has an output unit, which is used to to generate output signals like PWM.

Interrupt Vector Register

The Timer_A module has two interrupt vectors linked to it: TACCR0 interrupt vector TACCR0 Capture Compare Interrupt Flag (CCIFG) and Timer_A Interrupt Vector Register (TAIV) for all CCIFG flags and Timer_A Interrupt Flag (TAIFG).  The TACCR0 CCIFG has the highest priority of all the interrupts for Timer_A.  The TAIV is used to prioritise and combine the TACCR1 CCIFG, TACCR2 CCIFG and TAIFG flags.

Timer_A Registers

The Timer_A module is configured with software by setting the bits inside the various registers, which alter the timers parameters.  The image below list the various registers associated with the Timer_A module.

MSP430 Timer Tutorial Guide Timer_A Registers

Timer_A Control

This register determines where the clock is sourced from and how the clock is divided either by 1, 2, 4 or 8.  The timers control mode is also set here, whether it’s stopped, counts up, continuous or up/down.  The TAR , clock divider and count direction can also be reset with the TACLR bit being set.  Lastly the Timer_A interrupt enable/disable and interrupt pending flag are also found here.  A typical command for this register looks like this TA0CTL = TASSEL_2 + MC_1; or TA1CTL = TASSEL_2 + MC_1;

Timer_A Counter

The Timer_A registers or TAR holds the count of Timer_A.  A command using this register could look something like this depending on your application TAR = 4500-1;

Timer_A Capture/Compare 0

The Timer_A capture/compare register 0 or TACCR0, is used in two cases.  In compare mode this holds the value for comparison with the timer value in the TAR.  When in capture mode, the value in the TAR is copied into the TACCR0 when a capture is performed.  An example of the register code would be as follows TA0CCR0 = 200-1;. 

Timer_A Capture/Compare Control 0

The Timer_A capture/compare control register 0 or TACCTL0, is a 16 bit register used to determine how the TACCR0 is set-up.  The register controls whether the timer module is set to capture or compare.  The trigger edge for the capture mode can be set, as well as where the source originates from, either internal or external.  Asynchronous or synchronous operation can determined, as well as synchronised capture or compare input.  There are various output modes, which are used to determine the operation of PWM signals for example.  Also this register allows interrupts to enabled for the timer module.  An example of the register code would be as follows TA0CCTL0 = OUTMOD_7 + CCIE;.

Timer_A Capture/Compare 1

The Timer_A capture/compare register 1 or TACCR1.  Has the same operation as TACCR0.  An example of the register code would be as follows TA0CCR1 = 200-1;. 

Timer_A Capture/Compare Control 1

The Timer_A capture/compare control register 1 or TACCTL1, is a 16 bit register used to determine how the TACCR1 is set-up.  Has the same operation as TACCTL0.  An example of the register code would be as follows TA0CCTL1 = OUTMOD_7;.

Timer_A Capture/Compare 2

The Timer_A capture/compare register 2 or TACCR2.  Has the same operation as TACCR0.  An example of the register code would be as follows TA0CCR2 = 200-1;. 

Timer_A Capture/Compare Control 2

The Timer_A capture/compare control register 2 or TACCTL2, is a 16 bit register used to determine how the TACCR2 is set-up.  Has the same operation as TACCTL0.  An example of the register code would be as follows TA0CCTL2 = CCIE;. 

Timer_A Interrupt Vector

The Timer_A interrupt vector register or TAIV, is used to prioritise and combine the remaining interrupt flags.  When reading the TAIV it will give the value of the current interrupt, as well as clearing that interrupts flag.

 

Timer Example 1

This first example demonstrates the use of one timer, which is used to flash the MSP430G2253 Launchpad LED’s on and off.  The code snippet below only shows the timer set-up and the interrupt handler, as these are the most relevant parts.

The code is fairly short and quite simple to walk through, in line 5 we first load the TA0CCR0 with the value 3000.  Line 6 turns the interrupt on for the TA0CCR0 when it overflows.  Line 7 sets the clock source to ACLK (12kHz) and the counter to count-up mode.  So the interrupt is generated every 250mS approximately.  Line 9 sets the MSP430 to low power mode and enables interrupts.  Lines 12 to 22 are the interrupt handler for Timer0_A, this interrupt automatically clears when called.  Inside the interrupt handler, the variable Control is used to ensure the green LED flashes once for every time the red LED flashes four times.  The closing brace marks the end of the main function.

Example 1 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 Timer Tutorial Timer Example 1

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.

Timer Example 2

The second example demonstrates the use of two timers, which are used to output PWM signals on GPIO pins P1.2 and P2.1.  The timer set-up code and also the GPIO set-up code is shown below.  The clock was set to 8MHz for this example.

Before walking through the code, the image below is extracted from the MSP430G2253 datasheet, this shows GPIO pin P1.2 and it’s functions.  The line which is highlighted demonstrates P1.2 can be used as an input and output for Timer0_A.

MSP430 Timer Tutorial GPIO Pin Functions

Walking through the code starting with line 5, this sets GPIO pin P1.2 as an output.  Line 6 selects the function for GPIO pin P1.2, and in this case it is used for PWM.  Lines 7 and 8 perform the same operation, except they are for GPIO pin P2.1.  line 11 the TA0CCR0 is loaded with 200, this sets the PWM frequency to 40kHz approximately.  Line 12 sets the output mode to reset/set.  Line 13 sets the count value of TA0CCR1, which determines the PWM duty cycle, in this case 50%. Line 14 sets the clock used by the TA0CTL to SMCLK and the counter to count-up mode.  Lines 17 to 20 set-up Timer1_A in the same way as Timer0_A, except the frequency is set to 8kHz approximately.

The image below shows a capture from the oscilloscope for this code, GPIO pin P1.2 is shown on channel 1 and P2.1 is shown by channel 2.

MSP430 Timer Tutorial Dual PWM example

Example 2 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 Timer Tutorial Timer Example 2

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.

Timer Example 3

The third example demonstrates the use of two timers, using PWM generated by Timer0_A and a timed interrupt on Timer1_A to alter the duty cycle.  The PWM output is configured to output on GPIO pin P1.6.  As with the previous code examples, only the timer set-up code is shown. The clock was set to 1MHz for this example.

Lines 5 to 8 in this example are almost identical to lines 5 to 8 in the example 2 code.  The main difference is the PWM frequency is set to 1kHz (clock set to 1MHz) and the duty cycle is initially set to 0.1%.  Lines 11 to 13 set-up Timer1_A, this has a count of 4000 so generates an interrupt every 4mS.  Line 15 sets the MSP430 to low power mode and enables interrupts.

Lines 18 to 25 are the interrupt handler for Timer1_A, as with the first example this interrupt automatically clears when called.  Inside the interrupt the value stored in TA0CCR1 is added to the variable IncDec_PWM which is multiplied by 2 every time the interrupt handler is called.  IncDec_PWM is a global variable and assigned the value 1.  This equates to the value in TA0CCR1 being incremented or decremented by 2, therefore the duty cycle changes by 2 or (0.2%) every time the interrupt handler is called.  This equates to a transition time of approximately two seconds from high to low and low to high.  The final if statement inside the interrupt handler reverses the direction of the duty cycle, causing the LED to decrease in brightness until a value greater than 998 is reached, and increase in value when a value less than 2 is reached.

Example 3 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 Timer Tutorial Timer Example 3

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.

There is also one more additional example for the timer, which demonstrates the capture mode.  This is actually part of a another tutorial based around switch debouncing, the timer is used to capture the undesired pulses generated by a noisy switch.  You can find the additional code by browsing to the end of my Switch Debouncing Tutorial Pt/1.

C2000 Programming Model Guide

 

In this C2000 Programming Model Guide, the two basic approaches to programming on the C2000 will be over viewed using the C2000 Launchpad.  Some code examples will be shown, as well as a code execution speed test comparing the two methods.  All the code is written in Code Composer Studio (CCS) v5.5, with the latest version of ControlSuite released at the time of this article being posted.

TI provides all the documentation required for programming the C2000, which can be found here.

The Texas Instruments ControlSuite can be downloaded free of charge and includes support for two programming methods: Direct Register Access Model and Software Driver Model. There is also a third method, using Assembly language but that will not be covered here. Both of these models can be used independently or a combination of both can be used. Each model has advantages and disadvantages, which are summarised below.

Advantages Disadvantages
Direct Register Access Model Smaller code footprint, Faster code execution Statements are obscure, A detailed knowledge of each register is required
Software Driver Model Larger code footprint, Generally slower execution time Code is much more over viewable and understandable

Direct Register Access Model

The direct register access model writes values directly to the individual peripherals registers, if you have programmed the MSP430G Launchpad it uses a similar method.  All of the peripheral registers are defined in the corresponding header file contained in f2802x0_header/i/include, the image below shows this in CCS.

C2000 Programming Model Guide Direct Register Access f2802x_headers

The individual header files define the location of each register with respect to other registers within a peripheral, as well as the bit fields within each register.  This is all implemented using structures, the header files only define the structures they do not declare them.  A C source file is used to declare the structures with the physical memory of the device F2802x_GlobalVariablesDefs.c.  To use the direct register access model in an application, the file DSP28x_Project.h must be included in each source file were the register accesses are made.  An example of a direct register access statement can be found in the code snippet below, this particular call clears the ADC interrupt flag for ADC interrupt 1.

Software Driver Model

The software driver model uses an API provided by the peripheral driver library, which is used by applications to control the peripherals.  Before a peripheral can be used, the driver header file needs to be included and a handle to that peripheral initialised.  The code snippet below shows an example of this, illustrating the header file for the PWM peripheral, then the initialisation and finally two API function examples.

Writing An Application Using Both Models

To write an application that includes both the direct register access model and the software driver model, TI recommends the following:

  • Link driverlib.lib into your application (see below image)
  • Include DSP28x_Project.h in files you wish to use the direct register access model
  • Add /controlsuite/device_support/f2802x0/version/ to your projects include path (see below image)
  • Include driver header files from f2802x0_common/include in any source file that makes calls to that driver

C2000 Programming Model Guide Software Driver Model f2802x_common

Simple Code Execution Time Test Using An Oscilloscope

A simple test was devised to illustrate the main differences between these two models, this test is also useful for testing control and timing applications.  It has been used in a previous tutorial to access code execution time, which can be found here.

The C2000 clock is set to 60MHz for this test.  The code uses a timer which generates an interrupt every 100uS, when this interrupt is generated GPIO pin 19 is set high, the interrupt is then cleared.  There is also a continuous while loop running in the main program function, this has a statement/function which sets the GPIO pin 19 low.  So the sequence of events is as follows:

Every 100uS the interrupt handler is called -> GPIO pin 19 is set high -> The interrupt flag is cleared -> The program returns to the while loop and GPIO pin 19 is taken low

There is also one more piece of additional code added, a variable called control.  This variable is quite important as in between the interrupt calls, the code inside the while loop will still be executed.  Therefore if the GPIO pin low statement/function is partly way through executing when the interrupt is called, it will then return to this point and cause multiple timing traces on the oscilloscope.  This is due to the fact that there is an indeterminate time when the interrupt is called and what code is being executed at that time.  So using the if statement inside the while loop which uses the control variable, reduces these unknowns and ensures the code is far more predictable.

 

The code snippet below shows the code used in the main function, this code also demonstrates the equivalent direct register access statement to the software driver function for the GPIO pin 19 operation.

The next four images show screen captures from the oscilloscope, for the direct register access model and the software driver model.  It should be noted there is still a small variation in the timing as multiple traces are visible, hence two images are shown for each model allowing the variation to be calculated.

Direct Register Access lowest Pulse Width

C2000 Programming Model Guide Tutorial Direct Registry Access lowest

Direct Register Access Highest Pulse Width

C2000 Programming Model Guide Tutorial Direct Registry Access highest

Software Driver Lowest Pulse Width

C2000 Programming Model Guide Tutorial TI API command lowest

Software Driver Highest Pulse Width

C2000 Programming Model Guide Tutorial TI API command highest

What these oscilloscope traces show is the direct register access model clearly executes at a faster rate, the lowest and highest execution times are listed below for each model.

Direct Register Access Model:

  • Lowest = 2.92uS which equates to 176 Clock Cycles
  • Highest = 3.4uS which equates to 204 Clock Cycles

Software Driver Model:

  • Lowest = 6.64uS which equates to 399 Clock Cycles
  • Highest = 7.08uS which equates to 425 Clock Cycles

How the models are used is dependant on the application:  (1) If code size and execution time is not an issue it’s perfectly ok to use the software driver model.  (2) If code size is not an issue but certain aspects where speed of execution and timing are critical, then using both methods could be applicable.  (3) If code size and execution time are both critical, then the direct register access model is probably the best choice (Assembly language would be even better).

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.

EagleCad Tutorial Grid Size Unit Setting

 

The EagleCad Tutorial Grid Size Unit Setting will cover how to edit the EagleCad eagle.scr script file.  If you use EagleCad and find you want to use Mils or mm, or simple want to change the default grid settings, then this tutorial will show you how.  There is also some basic information on this on the EagleCad FAQ’s page located here.

This tutorial will concern itself with the eagle.scr script file, this deals with settings for the layouts, schematics and libraries.  There are two other script files called eagle.epf and a user specific eagler.usreagle.epf saves all the settings during work and eagle.usr contains user specific and global settings not associated with layouts, schematics and libraries, but things like window settings for example.

Before we go any further I use the mm setting mainly as I deal with metric measurements the majority of the time, I have access to a LPKP milling machine and all the drill bits are metric.  It is worth bearing in mind if you intend to send your Gerber files to a PCB fabrication house, ensure you are working within their requirements and tolerances.

The image below shows a screen capture of my EagleCad version 7 installation, the location for the script file can be seen as C:\EAGLE-7.0.0\scr\eagle.scr.  The location is the same for version 6 and I believe other versions as well, just the root EagleCad folder maybe different.

EagleCad Tutorial Grid Size Unit Setting eagle.scr file location

The next image shows the Eaglcad eagle.scr file opened in Notepad++, with the grid settings for the SCH (schematic) highlighted on line 16 (click to enlarge).  Also note the BRD (board) grid setting on line 10, this uses lines instead of dots.

EagleCad Tutorial Grid Size Unit Setting eagle.scr file open in NotePad++

So what does GRID MM 2.54 DOTS ON ALT MM 0.3175 actually mean, well you have probably guessed most of it already, but I will run through the meaning:

  • GRID – Specifies the grid command and the current unit which is MM
  • 2.54 – Sets the grid size to 2.54mm
  • DOTS – Sets the grid to be displayed as dots, LINES is an alternative option
  • ON – Sets the grid on as soon as you enter the schematic mode
  • ALT – Defines the alternate grid
  • MM – Sets the alternate units in this case to mm
  • 0.3175 – Sets the alternate grid size to 0.3175mm

 

The next image shows the result of this setting after the eagle.scr file were saved and EagleCad restarted and the schematics mode entered.

EagleCad Tutorial Grid Size Unit Setting eagle.scr gride size edited and saved

EagleCad also has a handy help file that gives you all these settings, as well as a few additional ones not mentioned.  Simply enter the help mode and search for grid, a screen capture of the help article is posted below.

EagleCad Tutorial Grid Size Unit Setting help file grid

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.

C2000 Solar MPPT Tutorial Pt/4

 

In this fourth and final part of the C2000 Solar MPPT Tutorial, the system set-up and testing will be looked at.  This will involve the overall hardware set-up for testing, ADC calibration, reduction of noise on the ADC sampling, efficiency test and some improvements for future iterations.  The final C2000 solar MPPT tutorial C code is also downloadable at the bottom of the page.

System Testing

Once the hardware was calculated and designed, the PCB was laid out and then printed using the freeware version of EagleCad.  The PCB was then printed on a LPKF milling machine, the finished component side of the PCB can be seen in the image below.

C2000 Solar MPPT Tutorial PCBThe board was given a thorough visual check, it was noted some of the drill holes on the component side were marginally out of alignment.  This is due to a slight misaligned of the milling machine alignment pins, the bottom of the PCB is milled first and then flipped so the component side can be milled.  When the board is flipped the minor misaligned becomes apparent, it is not enough to cause an issue, but I manually make all my own footprints allowing for the small idiosyncrasies and tolerances of the milling machine.

The components used for the design were mainly sourced from the education institution stock, with only the INA138 being ordered in.  This reduced any unwanted lead times and also keeps costs down.  There are down sides to this which were found with the IRFI640G MOSFETs.  The mistake was made of soldering these directly onto the PCB without checking the MOSFETs first, they were sourced from a large bag of perhaps 500 or more IRFI640G, all previously reclaimed from other boards.  Once the board was constructed it was noted the power supply was going straight into over current protection, this was narrowed down to two faulty MOSFETs that were short circuit, between Drain and Source.  A quick on the fly test I used to check the MOSFETs can be seen in the image below.

C2000 Solar MPPT Tutorial MOSFET Testing

System Calibration

Once the board was working, the next step was to test the buck circuits under controlled conditions,  The test involved the C2000 being set-up to supply a fixed PWM output of 50% duty cycle on PWM1, with PWM2 180o out of phase.  A dummy load in the shape of a 100W potentiometer set to 50Ω was connected to the output terminal, with a 20V supply applied to the solar panel input pins.  A multimeter was used to then measure the output DC voltage, which was observed to be 10V, this confirmed the buck circuit was operating correctly, the 20V was adjusted down to approximately 15V and the voltage was observed to half on the output.

After this initial test the ADC values being sampled needed to be calibrated, this would involve measuring the input voltage and current as well as the output voltage and current.  To achieve this to a good accuracy the same test conditions were used and two Hewlett Packard 34401A multimeter’s.  Some constant values were calculated from the signal conditioning circuitry (see the second part of this tutorial here) used to sample the ADC values, these were calculated as follows.

C2000 solar MPPT Tutorial ADC Constant Equations

These values would then need to be adjusted to meet the tolerances of the circuit.  A laptop was also set-up running Code Composer Studio (CCS) and the calculated ADC variables were viewed, and then the constant calculations values altered until the accuracy was satisfactory. The actual ADC constant values used can be seen in the below code snippet

Various test were carried out at this point to see how the ADC calibration and sampling was working, experimenting with sample and hold times, over sampling.  A useful tool is the graphing feature in CCS this allows trends to be observed in variables.  The original set-up used a timer to trigger the ADC sampling, however this generated more noise due to the MOSFET switching, so the PWM was used to trigger the ADC SOC.

 

The next image shows a screen capture from CCS, with the debug mode in operation.  The MPPT circuit was supplied with 17.5V from a regulated power supply, the load potentiometer was set to 40Ω, a PWM frequency of 25kHz (not 15kHz) with a 50% duty cycle was used in an open loop configuration.

C2000 Solar MPPT Tutorial 25kHz_25SH

What this graphed data shows is a 2 minute sample window (click the image to expand), the top graph is the input current with a variation of 2.4mA, and the bottom graph input volts with a variation of 10mV.  At the top right of the graph the ADC input variable values can also be seen, the two highlighted in yellow just indicates the value has just changed.

Efficiency Test

This basic efficiency calculation test was made by graphing the the input and output power under different power conditions.  The power efficiency fluctuated between 85~93%, with the greatest efficiency being achieved towards mid-range power.  The graphed data can be seen below with the input power at the top and the output power at the bottom.

C2000 solar MPPT Tutorial Power Efficiency Graph

Improvements

This was a prototype design and the first attempt at a solar MPPT, as such there are some improvements that can be made for future iterations.

On the software side, the clock speed for the C2000 could be reduced as there is plenty of idle time, the processor could also be placed into a low power mode between timer interrupts, this would bring an overall reduction in power dissipation.  Additionally a battery charging statement machine could be easily added, with a further form of regulation to switch between full charge and float charge.  If the circuit did not require an interleaved design, the code structure and algorithm could be easily ported across to a lower power and less expensive microcontroller like an MSP430G series.

On the hardware, the MOSFETs are key components that could be changed making the system more efficient.  Greater use of surface mount devices would reduce the circuit trace lengths and noise.  An improved ground plan design would also help reduce noise.  The trace lengths for each circuit phase ideally need to be identical, this will help to balance the phases.  It is possible to sample the current in each phase, then use software to adjust the duty cycle to correct any imbalances, however this increases the overall systems complexity particularly the software.

C2000 Solar MPPT Tutorial C Code Download

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.

C2000 Solar MPPT Tutorial Full 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.

C2000 Solar MPPT tutorial Pt/3

 

In this third part of the C2000 Solar MPPT Tutorial, the software will be looked at in greater detail.  This will entail a look at the Perturb & Observe algorithm, ADC code and timing code to ensure everything operates in a controlled manner.

The software is based around a Perturb and Observe (P&O) algorithm, the P&O algorithm falls under the category of a hill climbing algorithm.  Hill climbing algorithms are named so due to the algorithm taking steps over sampled data to reach a desired value, in the case of the P&O this takes steps towards the MPP by increasing or decreasing the duty cycle.  There are other hill climbing algorithms such as dP/dV Feedback Control and Incremental Conductance, I intend to revisit these and write code at a later date, but for now will focus on the P&O.  Some further information on MPPT algorithms can also be found here.

Perturb & Observe Algorithm

The P&O algorithm is a relatively simple algorithm, as such it has a few drawbacks:

  • The algorithm can be confused and track in the wrong direction, this can occur under fast changing irradiance conditions, the severity of this confusion depends on the P&O setup i.e. step size and update frequency.
  • The algorithm oscillates around the set point showing characteristics of an on/off controller.  More on this can be found on a previous tutorial I wrote regarding PID control, which can be found here.

The flowchart below shows the P&O algorithm used for this project

C2000 Solar MPPT Tutorial Perturb and Observe Algorithm Flow Chart

As can be seen from the flowchart the algorithm is fairly easy to follow, turning this into C code is also relatively easy, the final C code P&O algorithm can be seen below inside the function Adj_PWM().

So lets now run through the code briefly starting with line 3, this basically assigns the value in the counter compare A register to variable PWM_Temp.  PWM_Temp could simply be assigned to a temporary global variable, but I chose to get it straight from the register in this case.  Lines 5 to 24 form the main body of the algorithm, looking back at the flowchart the first two steps “Sample” and “Calculate” are carried out elsewhere in the ADC section of the code.  Lines 5 to 14 are illustrated by the right hand branch of the flowchart and lines 15 to 24 are illustrated by the left hand branch of the flowchart.

You have some simple if and else statements that determine which direction the algorithm takes, which is dependant on the sampled ADC data.  The result of these steps will either increase or decrease the PWM duty cycle, this increase or decrease determines the step size and in this case that value is 2.

The next block of code from lines 26 to 31 are used to prevent the duty cycle from reaching too large, and too small a value.  This was used during tuning, but also serves to provide some boundaries for the PWM, for example the duty cycle for the half bridge MOSFET drivers cannot exceed 99%, or the boost function will not operate correctly.

Lines 32 and 33 are used to update the duty cycle to the counter compare A registers for PWM1 and PWM2, both are the same duty cycle but PWM2 is 180o out of phase with PWM1.  Line 35 then assign the latest calculated solar panel voltage IP_Volt to the variable Old_IP_Volt and line 36 assign the latest calculated solar panel power New_PW_In to the variable Old_PW_In, both these variables are then used when the Adj_PWM() function is called again.

In order to help visualise the two PWM signals, the below image shows an oscilloscope trace with PWM1 in yellow and PWM2 in blue, both are set to 50% duty cycle and PWM2 is out of phase by 180o with PWM1.

C2000 Solar MPPT Tutorial 50% Duty 180 Phase

ADC Code

The next piece of code to be looked at is the ADC, I am not going to show the set-up code for the ADC or the PWM that triggers the ADC SOC, but will just show the code relating to the sampling and calculation.  However I intend to write a tutorial on each peripheral inside the C2000 with code examples, when time allows.  The ADC sampling is triggered by the PWM on every first event, therefore the sampling rate is 15ksps.  The final ADC sampling code can be seen below inside the function Data_Update()

So starting with lines 3 to 6 these are the local variables used for the function, the two floats are used to store the ADC values and the two integers are used to determine how many samples in the for loop.  The float in line 4 is a float array with four arrays, now the same result could be achieved with four separate floats.  I have left it as a float array for now, but if four floats were used the code should be optimised, by using 64 samples the following division of 128 (lines 23 to 26) could be substituted with a right bit wise shift of 7.

Lines 8 to 21 consist of the for loop, this uses the integer i as a counter and numberOfsamples as the count value.  Inside the for loop shown on line 10 this statement will wait until the next PWM trigger is received, which then initiates the ADC SOC channel number 0, once ADC channel 0 is finished it initiates channel 1 and so on and so forth.  The samples are saved in each of the channel numbers registers, then using the += addition assignment operator are added to the sum_of_ADC_samples_Array[n].  So an accumulated value is built up of the total samples every time the for loop is executed.  In addition there are 8 ADC channels being sampled, channel 0 to 7, but only 4 samples are accumulated so ADC channel 0 and 4 are added to sum_of_ADC_samples_Array[0] and channel 1 and 5 are added to sum_of_ADC_samples_Array[1] and so on and so forth.  When the ADC channel sampling sequence has finished, the trigger flag for the SOC sequence is cleared (line 20) and the loop waits for the next trigger event from the PWM.  Once i reaches 64 the loop is exited, each of the of the sum_of_ADC_samples_Array[n] now have 128 accumulated sample values in.

Lines 23 to 26 divide the sum_of_ADC_samples_Array[n] by 128 and assign the value to ADC_An floats.  Lines 28 to 31 convert the new floats to real world voltages read on the GPIO. Lines 33 to 36 then use constant values calculated from the electronic component values in the circuitry, to convert the floats to actual voltages and currents sampled in the circuit.  Lines 38 to 40 simply convert the input voltage and current to an input power and the output voltage and current to an output power.

 

Timing Code

The timing code is quite critical as it determines the update frequency of the MPPT, it must also ensure the code does not overrun and cause unpredictable behaviour.  The internal timer module was used, Timer 0 was set-up to trigger an interrupt every 100mS or 10Hz. The interrupt code is shown below.

When the interrupt is called an integer called SysTick is set to one, then the interrupt flag is cleared allowing the interrupt request to be executed and exited quickly.

Inside the main function there is a continuous while loop, the following code is run inside this loop.

Every time the interrupt sets the integer called SysTick to one, it allows the functions Data_Update() and Adj_PWM() to be executed, once these functions have completed SysTick is set to zero.  There are some additional lines of code on line 5 and line 10, these are used for testing and allowing the code execution time to be displayed on an oscilloscope.  The code on line 5 switches GPIO pin 19 high, then the code on line 10 switches GPIO pin 19 back to low, so a square wave pulse is produced and the pulse width gives an indication of the code execution time of the functions Data_Update() and Adj_PWM(). The following images show captures from an oscilloscope.

C2000 solar MPPT PWM and MPPT update frequency

This first image shows the 15kHz PWM being displayed on channel 1, the individual wave pulses are not visible as the time base is set to display channel 2.  The blue trace shown on channel 2 can be seen to have a frequency of 10Hz, with a pulse width of 4.4mS, so the functions Data_Update() and Adj_PWM() take 4.4mS to execute.  Putting this into context there should be 128 ADC samples captured, taken from 64 triggers of the PWM signal, therefore 64*66.67uS (one 15kHz cycle) = 4.27mS.  A single ADC sample and conversion takes around 650nS, if we multiply that by the 8 samples, a conversion is being completed every 8*650nS = 5.2uS (it will be faster than this due to ADC pipelining effects).  It can be clearly seen that there is plenty of room for more oversampling if required, as the 5.2uS sample and conversion time easily fits inside the 66.67uS window of the PWM trigger.  There is also a small amount of code overhead being added artificially by toggling GPIO pin 19, which is not significant but something to be aware of.

C2000 solar MPPT PWM and MPPT update frequency zoomed

The second image has a smaller time base setting (100uS) effectively zooming in, which allows the individual pulses from the 15kHz PWM to be visible.  So going back to the step size of 2 shown in the Adj_PWM() function, this can be put into context when the maximum duty cycle value as a variable, for 100% duty cycle equals 1000.  Therefore with a PWM update frequency of 10Hz and a maximum step size of 2, this equates to a maximum duty cycle change of 2% per second.

I captured some video which shows 3 variables being graphed in Code Composer Studio, these variables are PV Power, PV Volts and the Duty Cycle.  The video also demonstrates the MPPT in action under simulated fast changing cloud conditions, as well as some natural cloud.

There will be one final part to this series of tutorials this will cover some of the set-up and testing, and will also include a link to the full C code for the project.

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.