<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>MSP430 - OCFreaks!</title>
	<atom:link href="https://www.ocfreaks.com/tag/msp430/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.ocfreaks.com/tag/msp430/</link>
	<description>Overclocking , Gaming , Technology , Robotics &#38; DIY!</description>
	<lastBuildDate>Wed, 25 Jul 2018 17:04:07 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.6.4</generator>
<site xmlns="com-wordpress:feed-additions:1">42777727</site>	<item>
		<title>MSP430 Timer Programming Tutorial</title>
		<link>https://www.ocfreaks.com/msp430-timer-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/msp430-timer-programming-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Sun, 22 Jul 2018 12:12:35 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[MSP430]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3099</guid>

					<description><![CDATA[<p>In this tutorial we will go through MSP430 Timer programming for MSP430x2xx devices like MSP430G2553, MSP430G2231 found on Launchpad development board. We will also cover two timer examples.</p>
<p>The post <a href="https://www.ocfreaks.com/msp430-timer-programming-tutorial/">MSP430 Timer Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="tocpostimage">In this tutorial we will go through MSP430 Timer programming for MSP430x2xx devices like <strong>MSP430G2553, MSP430G2231</strong> found on Launchpad development board. MSP430G2 devices have two 16-bit timers i.e. <strong>Timer_A and Timer_B</strong>. Timer_B is slightly different than Timer_A and also has few more features, but it is <strong>NOT</strong> implemented in both MSP430G2553 and MSP430G2331 micro-controllers. Hence, we will focus on <strong>Timer_A</strong> for this tutorial.</p>
<div class="toc_container">
<span class="toc_title">Table of Contents</span></p>
<div class="toc">
<ol class="toc_list">
<li class="toc_text"><a href="#Intro"><span>Introduction</span></a></li>
<li class="toc_text"><a href="#Timer_Regs"><span>MSP430 Timer Registers</span></a></li>
<li class="toc_text"><a href="#Timer_Config"><span>Configuring &#038; Setting Up Timer in MSP430</span></a></li>
<li class="toc_text"><a href="#Timer_Formulae"><span>Handy MSP430 Timer Formulae for delay calculations</span></a></li>
<li class="toc_text"><a href="#Timer_Examples"><span>MSP430 Timer Examples</span></a></li>
<ol class="toc_list">
<li class="toc_text"><a href="#Example_1"><span>A simple Delay function using Interrupt</span></a></li>
<li class="toc_text"><a href="#Example_2"><span>Blinky using MSP430 Timer Interrupt</span></a></li>
</ol>
</ol>
</div>
</div>
<h2 class="shead" id="Intro" style="margin-top:5px;">Introduction</h2>
<p>MSP430G2553 has two Timer_As viz. <strong>Timer0_A3</strong> and <strong>Timer1_A3</strong> which features 3 capture/compare registers while MSP430G2231 has only 1 timer called <strong>Timer0_A2</strong> with only 2 capture/compare registers. In addition to Capture, Timer_A also supports PWM outputs and interrupts. They also include a Watchdog Timer (WDT+) which I will discuss in another tutorial.</p>
<div class="special sp_blue noteinfo">The naming convention used in datasheet is &#8220;<strong>Timer<em>n</em>_A<em>x</em></strong>&#8221; where <strong>n</strong> = Timer module number, <strong>x</strong> = no. of. capture/compare registers supported.</div>
<p>Timer_A supports four different clock sources: ACLK, SMCLK and 2 external sources: TACLK or INCLK. The selected clock source can then be divided by 1,2,4 or 8. The register used for counting is called TAR(16-bit R/W) and can increment or decrement for each rising edge of clock signal. Compared to Timer blocks of other microcontrollers, these MCUs don&#8217;t support prescaler.  </p>
<h4>Timer Modes:</h4>
<p><strong>Timer_A supports 4 modes of operation:</strong></p>
<ol style="margin-bottom:10px;">
<li><strong>Stop Mode:</strong> In this mode the Timer is Halted.</li>
<li><strong>Up Mode:</strong> Timer repeatedly counts from Zero to value stored in Capture/Compare Register 0 (TACCR0).</li>
<li><strong>Continuous:</strong> Timer repeatedly counts from Zero to 0xFFFF, which is maximum value for 16-bit TAR.</li>
<li><strong>Up/Down Mode:</strong> Timer repeatedly counts from Zero up to the value in TACCR0 and back down to zero.</li>
</ol>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/msp430-tutorial/msp430_timer_modes.png" width="470px" height="620px" alt="Timer Modes in MSP430 microcontrollers"></p>
<h2 class="shead" id="Timer_Regs">MSP430 Timer Registers</h2>
<p><strong>1) <span class="doc_ref">TAR</span> &#8211; Timer Counter Register:</strong> Holds the current count for Timer_A.</p>
<p><strong>2) <span class="doc_ref">TACCRx</span> &#8211; Timer Capture/Compare Register:</strong> In Compare mode, it holds compare value to be compared against TAR. In Capture mode, it holds the current value of TAR when a capture is performed. Maximum value it can store is 0xFFFF since its a 16 bit register.</p>
<p><strong>3) <span class="doc_ref">TACTL</span> &#8211; Control Register:</strong> Used to configure Timer_A. This register is divided as follows:</p>
<ul>
<li><strong>Bit[0] &#8211; <span class="doc_ref">TAIFG</span> &#8211; Timer_A Interrupt Flag</strong>. 0 = No interrupt pending, 1 = Interrupt pending.</li>
<li><strong>Bit[1] &#8211; <span class="doc_ref">TAIE</span> &#8211; Timer_A Interrupt Enable.</strong> 0 = Interrupt Disabled, 1 = Interrupt Enabled.</li>
<li><strong>Bit[2] &#8211; <span class="doc_ref">TACLR</span> &#8211; Timer_A clear.</strong> Setting this bit resets TAR, clock divider, and the count direction. It is automatically reset and is always read as zero.</li>
<li><strong>Bits[5:4] &#8211; <span class="doc_ref">MCx</span> &#8211; Mode Control bits.</strong> Used to select between 4 different modes as given:<br />
[00] = MC_0 &#8211; Stop mode: Timer is halted.<br />
[01] = MC_1 &#8211; Up mode: Timer counts up to TACCR0.<br />
[10] = MC_2 &#8211; Continuous mode: Timer counts up to 0xFFFF.<br />
[11] = MC_3 &#8211; Up/down mode: Timer counts up to TACCR0 then down to 0x0000.</li>
<li><strong>Bit[7:6] &#8211; <span class="doc_ref">IDx</span> &#8211; Input divider.</strong> Selects input clock divider.<br />
[00] = ID_0 &#8211; /1<br />
[01] = ID_1 &#8211; /2<br />
[10] = ID_2 &#8211; /4<br />
[11] = ID_3 &#8211; /8</li>
<li><strong>Bits[9:8] <span class="doc_ref">TASSELx</span> &#8211; Timer_A clock source select.</strong><br />
[00] = TASSEL_0 &#8211; TACLK<br />
[01] = TASSEL_1 &#8211; ACLK<br />
[10] = TASSEL_2 &#8211; SMCLK<br />
[11] = TASSEL_3 &#8211; INCLK (check datasheet)</li>
<li>Other Bits &#8211; Reserved</li>
</ul>
<p><strong>3) <span class="doc_ref">TACCTLx</span> &#8211; Capture/Compare Control Register:</strong> Used to configure capture/compare options. I will only cover the parts of this register which are applicable to this tutorial. We will see it in detail in other tutorials(for Capture mode &#038; PWM).</p>
<ul>
<li><strong>Bit[0] &#8211; <span class="doc_ref">CCIFG</span> &#8211; Capture/compare interrupt flag:</strong> 0 = interrupt pending, 1 = Interrupt pending.</li>
<li><strong>Bit[4] &#8211; <span class="doc_ref">CCIE</span> &#8211; Capture/compare interrupt enable:</strong> This bit enables the interrupt request of the corresponding CCIFG flag. 0 = Interrupt disabled = 1 Interrupt enabled.</li>
<li><strong>Bit[8] &#8211; <span class="doc_ref">CAP</span> &#8211; Capture mode:</strong> Used to select between Compare and Capture mode. We will this bit in its default setting i.e. = 0. 0 = Compare mode, 1 = Capture mode.</li>
</ul>
<p><strong>4) <span class="doc_ref">TAIV</span> &#8211; Interrupt Vector Register:</strong> Used to identify the flag which requested an interrupt. This is a read only register and only uses 3 bits [3:1] called TAIVx. The values for TAIVx which corresponds to various sources is as given below:</p>
<ul>
<li>0x00 = No Interrupt Pending.</li>
<li>0x02 = Capture/Compare 1 &#8211; TACCR1 CCIFG.</li>
<li>0x04 = Capture/Compare 2 &#8211; TACCR2 CCIFG.</li>
<li>0x0A = Timer(TAR) Overflow &#8211; TAIFG.</li>
<li>Other &#8211; Reserved.</li>
</ul>
<div class="special sp_blue noteinfo"><strong>Timer Register Naming Convention:</strong> Using the register names as given in user manual will default to Timer0_A3 registers. For e.g. TACTL is same as TA0CTL. Note that Timer registers are defined as TA<strong>n</strong>CTL, TA<strong>n</strong>CCR0 and so on.. where <strong>n</strong> = Timer module number(in our case 0 or 1). For Timer1_A3 these names will be TA<strong>1</strong>CTL, TA<strong>1</strong>CCR0 and so on. TA<strong>0</strong>CTL and other Timer0_A3 are just redefined as TACTL, TACCR0 and so on. </div>
<h2 class="shead" id="Timer_Config">Configuring &#038; Setting Up Timer in MSP430</h2>
<p>Given, clocks are configured properly, <strong>basic setup</strong> of Timer_A can be done follows:</p>
<ul style="margin-bottom:10px;">
<li>Set the Compare value in <span class="code_var">TACCR0</span> if using Up mode or Up/Down mode. Timer may be stopped by using <span class="code_var">TACCR0 = 0;</span> and can be started/restarted any time by writing a non-zero compare value in <span class="code_var">TACCR0</span> whenever Timer is to be used. Total Counts by timer will be <span class="code_var">TACCR0 + 1</span>.</li>
<li>Set CCIE(Capture/Counter Interrupt Enable) bit in <span class="code_var">TACCTL0</span> to enable interrupt for <strong>CCR0</strong>. We also keep the CAP bit to default value(=0) to enable Compare mode.</li>
<li>Select Clock Source, Input Clock divider and Timer mode using <span class="code_var">TASSELx, IDx, MCx</span> fields respectively.</li>
<li>Enable global Interrupts and we are done.</li>
</ul>
<div class="special sp_yellow noteinfo">Note that TACCR0 has dedicated interrupt vector. Other TACCRx have common interrupt vector(see TAIVx and section 12.2.6 on page 367 in User Manual).</div>
<p>In examples given below we will use Up mode with input clock source as SMCLK(MCx = MC_1) without an divider(IDx = ID_0 i.e. divide by 1). We will set MCLK and SMCLK to run at 1MHz, both sourcing clock from DCO. This is the default configuration.</p>
<pre><code class="language-cpp">
TACCR0 = ..; //Compare Value for TAR
TACCTL0 |= CCIE; //Enable interrupt for CCR0.
TACTL = TASSEL_2 + ID_0 + MC_1; //Select SMCLK, SMCLK/1 , Up Mode
_enable_interrupt();
/* More code */
</code></pre>
<h2 class="shead" id="Timer_Formulae">Handy MSP430 Timer Formulae for delay calculations</h2>
<p>Formula for amount of time taken to increment TAR count by 1 is given as:</p>
<div class="equation" style="font-size:16px;margin-bottom:10px;">Resolution(Delay per TAR Count) in Seconds = </p>
<div class="fraction"><span class="fup">DIV</span><span class="bar">/</span><span class="fdn">Input Clock in Hz</span></div>
</div>
<p>where DIV = Input Clock divider either 1,2,4 or 8.</p>
<p><strong>E.g.:</strong> When using divider of /2 and Input clock of 4MHz we get timer resolution as,</p>
<div class="equation" style="font-size:15px;margin-bottom:10px;">Resolution = </p>
<div class="fraction"><span class="fup">2</span><span class="bar">/</span><span class="fdn">4 x 10<sup>6</sup>Hz</span></div>
<p>Seconds = 0.5 x 10<sup>-6</sup> Seconds = 0.5 µS</div>
<p>The time required for TAR to count from 0 and reach TACCR0 (i.e. overflow or TAR period) is given as:</p>
<div class="equation" style="font-size:16px;margin-bottom:10px;">Timer Period in Seconds = </p>
<div class="fraction"><span class="fup">DIV x (TACCR0 + 1)</span><span class="bar">/</span><span class="fdn">Input Clock in Hz</span></div>
</div>
<p>We subtract 1 from TACCR0 since TAR counts &#8220;TACCR0+1&#8221; times to overflow. This is because count starts from 0.</p>
<p><strong>E.g.:</strong> When using divider of /2, Input clock of 4MHz and TACCR0 = 1000-1 = 999, we get Timer Period as,</p>
<div class="equation" style="font-size:15px;margin-bottom:10px;">Timer Period = </p>
<div class="fraction"><span class="fup">2 x (999 + 1)</span><span class="bar">/</span><span class="fdn">4 x 10<sup>6</sup>Hz</span></div>
<p> = 0.5 x 1000 x 10<sup>-6</sup> S = 500 µS</div>
<h2 class="shead" id="Timer_Examples">MSP430 Timer Examples</h2>
<p>Now, lets cover 2 Timer examples. Both examples are valid for MSP430G2553 , MSP430G2231 and similar MCUs.</p>
<h4 id="Example_1">Example 1: A simple Delay function using Interrupt</h4>
<p>Of-course, we have the option of using inbuilt function <span class="code_var">__delay_cycles(..)</span>, but wheres the fun if we don&#8217;t implement a similar function using Timer? Anyways, in this example we will define a function called <strong><span class="code_var">delayMS(int msec)</span></strong> which generates delay as per given input in mill-seconds. This function is used in conjunction with Timer_A Interrupt for <strong>CCR0</strong>. The time is counting, ISR continuously increments an Overflow counter when <span class="code_var">TAR</span> reaches value in <span class="code_var">TACCR0</span>. We set the value in <span class="code_var">TACCR0</span> such that counting from 0 to <span class="code_var">TACCR0</span> takes exactly 1ms, and hence we get a resolution of 1ms for our delay function. This function will give more accurate delay as MCLK increases, since it contains a few statements which eat up proportionate amount CPU cycles. Now, since we are using <strong>Timer Clock = 1MHz</strong> (SMCLK=1MHz), 1000 ticks will equal to 1ms. Hence, we use <span class="code_var">TACCR0 = 1000</span> inside delay function. In general for <strong>Y</strong> MHz timer clock, <strong>Y</strong> x 1000 ticks are required for 1ms delay. Before exiting the function we use <span class="code_var">TACCR0 = 0</span> to stop the Timer.</p>
<pre><code class="language-cpp">
#include &lt;msp430.h&gt;

void initTimer_A(void);
void delayMS(int msecs);

unsigned int OFCount;

int main(void)
{
	WDTCTL = WDTPW + WDTHOLD; //Stop watchdog timer
	P1DIR |= BIT0; //Configure P1.0 as Output

	//Set MCLK = SMCLK = 1MHz
	BCSCTL1 = CALBC1_1MHZ;
	DCOCTL = CALDCO_1MHZ;

	initTimer_A();
	_enable_interrupt();

	while(1)
	{
		P1OUT |= BIT0; //Drive P1.0 HIGH - LED1 ON
		delayMS(500); //Wait 0.5 Secs

		P1OUT &= ~BIT0; //Drive P1.0 LOW - LED1 OFF
		delayMS(500); //Wait 0.5 Secs
	}
}

void initTimer_A(void)
{
	//Timer0_A3 Configuration
	TACCR0 = 0; //Initially, Stop the Timer
	TACCTL0 |= CCIE; //Enable interrupt for CCR0.
	TACTL = TASSEL_2 + ID_0 + MC_1; //Select SMCLK, SMCLK/1, Up Mode
}

void delayMS(int msecs)
{
	OFCount = 0; //Reset Over-Flow counter
	TACCR0 = 1000-1; //Start Timer, Compare value for Up Mode to get 1ms delay per loop
	//Total count = TACCR0 + 1. Hence we need to subtract 1.

	while(i<=msecs);

	TACCR0 = 0; //Stop Timer
}

//Timer ISR
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A_CCR0_ISR(void)
{
	OFCount++; //Increment Over-Flow Counter
}
</code></pre>
<h4 id="Example_2">Example 2: Blinky using MSP430 Timer Interrupt</h4>
<p>In this example, instead of using a dedicated delay function we place the blinky code inside the Timer_A Interrupt itself. The Timer initialization code is same as before. The Timer is never stopped and it repeatedly restarts counting when <span class="code_var">TAR</span> reaches <span class="code_var">TACCR0</span> to generate 1ms delay. Similar to previous example, an overflow counter is maintained by ISR itself. We just need to define how much delay(in ms) we require. This is done by defining a MACRO <span class="code_var">BLINKY_DELAY_MS</span>. Also, note that we won't be using Low Power Mode (LMP0). If you want to use LMP0 than make sure <span class="code_var">TACCR0</span> has a suitable maximum value along with higher clock divider, so CPU stays disabled most of the time. In our case we can use <span class="code_var">TACCR0 = 50000;</span> and use overflow count limit of 10 for 500ms delay. In this way the ISR is called every 50ms when clock divider is 1, and every 200ms when clock divider is 4.</p>
<pre><code class="language-cpp">
#include &lt;msp430.h&gt;
#define BLINKY_DELAY_MS 500 //Change this as per your needs

void initTimer_A(void);
void delayMS(int msecs);

unsigned int OFCount;

int main(void)
{
	WDTCTL = WDTPW + WDTHOLD; //Stop watchdog timer
	P1DIR |= BIT0; //Configure P1.0 as Output

	//Set MCLK = SMCLK = 1MHz
	BCSCTL1 = CALBC1_1MHZ;
	DCOCTL = CALDCO_1MHZ;

	initTimer_A();
	_enable_interrupt();

	OFCount  = 0;
	TACCR0 = 1000-1; //Start Timer, Compare value for Up Mode to get 1ms delay per loop
	/*Total count = TACCR0 + 1. Hence we need to subtract 1.
	1000 ticks @ 1MHz will yield a delay of 1ms.*/

	while(1);
}

void initTimer_A(void)
{
	//Timer Configuration
	TACCR0 = 0; //Initially, Stop the Timer
	TACCTL0 |= CCIE; //Enable interrupt for CCR0.
	TACTL = TASSEL_2 + ID_0 + MC_1; //Select SMCLK, SMCLK/1 , Up Mode
}

//Timer ISR
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A_CCR0_ISR(void)
{
	OFCount++;
	if(OFCount >= BLINKY_DELAY_MS)
	{
		P1OUT ^= BIT0;
		OFCount = 0;
	}
}
</code></pre>
<p>The post <a href="https://www.ocfreaks.com/msp430-timer-programming-tutorial/">MSP430 Timer Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/msp430-timer-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3099</post-id>	</item>
		<item>
		<title>MSP430 GPIO Programming Tutorial</title>
		<link>https://www.ocfreaks.com/msp430-gpio-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/msp430-gpio-programming-tutorial/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Mon, 11 Dec 2017 18:09:37 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[MSP430]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=3038</guid>

					<description><![CDATA[<p>In this tutorial we will learn MSP430 GPIO Programming and cover some Basic Digital I/O Examples to get you started with MSP430. This tutorial is also applicable for MSP430x2xx devices like MSP430G2553, MSP430G2231, etc found on Launchpad Development board.</p>
<p>The post <a href="https://www.ocfreaks.com/msp430-gpio-programming-tutorial/">MSP430 GPIO Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this tutorial we will learn MSP430 GPIO Programming. It is also applicable for MSP430x2xx devices like MSP430G2553, MSP430G2231, etc found on Launchpad Development board. Most of the pins on MSP430 Microcontrollers are grouped into a maximum of 8 <strong>Ports</strong> viz. P1 to P8. Each port is 8-bits wide and has eight associated I/O pins. These pins are directly mapped to the corresponding port registers and hence I/O pins can be manipulated independently. Only pins in Ports P1 and P2 support interrupts. Additionally, each I/O pin also has configurable pull-up and pull-down resistors. Each port has an associated groups of registers used to manipulate its individual pins. The bit mapping and port grouping is as shown below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/msp430-tutorial/msp430_pin_mapping.png" alt="MSP430 Digital I/O Port Pin to Register Mapping" width="325px" height="220px" /></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/msp430-tutorial/msp430_gpio_registers.png" alt="MSP430 GPIO registers" width="475px" height="135px" /></p>
<div class="special sp_blue noteinfo">The naming convention(as used in the Manual/Datasheet) for Pins is ‘<strong>Px.y</strong>’ where ‘<strong>x</strong>’ is the port number (1 to 8) and ‘<strong>y</strong>’ is simply the pin number (0 to 7) in port ‘<strong>x</strong>’. For example : <strong>P1.1</strong> refers to Pin number <strong>1</strong> of Port <strong>1</strong> , <strong>P2.4</strong> refers to Pin number <strong>4</strong> in Port <strong>2</strong>. You will see the same conventions used to mark pins on your MSP430 Launchpad development board.</div>
<p>Current version of MSP430G2 Launchpad Ships with MSP430G2553 and MSP430G2452. Older version(Rev1.4) used to ship with MSP430G2231 and MSP430G2211. However, programming is same for all supported devices unless mentioned.</p>
<h2 class="shead">GPIO Registers in MSP430</h2>
<p>The GPIO block has many registers. We will only go through some of the digital I/O registers that are within the scope of this tutorial. I will cover Interrupt related registers(viz. <span class="doc_ref">PxIFG</span>, <span class="doc_ref">PxIES</span>, <span class="doc_ref">PxIE</span>) in a different tutorial.</p>
<div class="highlight">
<p><strong>1. <span class="doc_ref">PxDIR</span>:</strong> This is the GPIO direction control register. Setting any bit to 0 in this register will configure the corresponding Pin[0 to 7] to be used as an Input while setting it to 1 will configure it as Output.</p>
<p><strong>2. <span class="doc_ref">PxIN</span> (Readonly):</strong> Used to Read values of the Digital I/O pins configured as Input. 0 = Input is LOW, 1 = Input is HIGH.</p>
<p><strong>3. <span class="doc_ref">PxOUT</span>:</strong> Used to directly write values to pins when pullup/pulldown resistors are disabled. 0 = Output is LOW, 1 = Output is HIGH. When pullup/pulldown resistors are enabled: 0 = Pin is pulled down, 1 = Pin is pulled up.</p>
<p><strong>4. <span class="doc_ref">RxREN</span>:</strong> For pins configured as input, PxREN is used to enable pullup/down resistor for a given pin and PxOUT in conjunction with PxREN is used to select either Pullup or pulldown resistor. Setting a bit to 1 will enable pullup/down resistor for the corresponding pin while setting it to 0 will disable the same.</p>
<table class="ocf-table">
<tr>
<th>PxDIR</th>
<th>PxREN</th>
<th>PxOUT</th>
<th>I/O Config</th>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>X</td>
<td>Input with resistors disabled</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
<td>0</td>
<td>Input with Internal Pulldown enabled</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
<td>1</td>
<td>Input with Internal Pullup enabled</td>
</tr>
<tr>
<td>1</td>
<td>X</td>
<td>X</td>
<td>Output &#8211; PxREN has no effect</td>
</tr>
</table>
<p><strong>5. <span class="doc_ref">PxSEL</span> &#038; <span class="doc_ref">PxSEL2</span>:</strong> Since most of the port pins are multiplexed with upto 4 different functions, we need a mechanism to select these functions. This is achived using PxSEL and PxSEL2 registers. The bit combinations of these registers for a particular pin will select a particular pin function. The bit combination is as given below:</p>
<table class="aligncenter ocf-table">
<tr>
<th>PxSEL2(nth bit)</th>
<th>PxSEL(nth bit)</th>
<th>Pin Function</th>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>GPIO (Digital I/O) Function</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
<td>Primary Peripheral Function</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
<td>Reserved. Consult device specific datasheet.</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>Secondary Peripheral Function</td>
</tr>
</table></div>
<p>Also note that <span class="doc_ref">PxSEL/PxSEL2</span> registers do not change the pin directions as required by the module function. Make sure you set the proper pin direction, as required by the alternate function, using PxDIR register.</p>
<h2 class="shead">MSP430 GPIO Programming &#038; Example Code in C/C++</h2>
<p><strong>Prerequisite:</strong> Before we start programming gpio you need to have basic understanding of Binary and Hexadecimal system and Bitwise operations in C/C++, here are two tutorials which can go through (or if you are already acquainted with these you can skip these and continue below) : </p>
<ul>
<li><a href="https://www.ocfreaks.com/hexadecimal-and-binary-number-system-basics-for-embedded-programming/">Hexadecimal and Binary Number System basics for Embedded Programming</a></li>
<li><a href="https://www.ocfreaks.com/tutorial-embedded-programming-basics-in-c-bitwise-operations/">Tutorial : Embedded programming basics in C – bitwise operations</a></li>
</ul>
<p><span class="code_var">msp430.h</span> is common header for all MSP430 devices. This header identifies your device and accordingly includes the device specific header. Each of the device specific headers also include bit definitions viz. from <span class="code_ref"><strong>BIT0</strong></span> to <span class="code_ref"><strong>BITF</strong></span>. Where <span class="code_ref"><strong>BITn</strong></span> is equivalent to <span class="code_var">(1&lt;&lt;n)</span> i.e the nth bit location is a 1 and rest bits are 0s.</p>
<p>Now lets see how we can assign values to registers. We can use Hexadecimal notation &#038; decimal notation for assigning values. If your compiler supports other notations like binary notation use can use that too. Lets say, we want to set <strong>PIN 6</strong> of <strong>Port 1 as output</strong>. It can be done in following ways:</p>
<pre><code class="language-cpp">
CASE 1. P1DIR = (1<<6); //(binary using left shift - direct assign: other pins set to 0)

CASE 2. P1DIR |= 0x20; //or 0x20; (hexadecimal - OR and assign: other pins not affected)

CASE 3. P1DIR |= (1<<6); //(binary using left shift - OR and assign: other pins not affected)

CASE 4. P1DIR |= BIT6; //Same as above, use Standard BIT definitions
</code></pre>
<ul>
<li>In many scenarios, Case 1 must be avoided since we are directly assigning a value to the register. So while we are making P1.6 '1' others are forced to be assigned a '0' which can be avoided by <strong>ORing</strong> and then assigning Value.</li>
<li>Case 2 can be used when bits need to be changed in bulk and</li>
<li>Case 3(and 4) can be used when some or single bit needs to be changed.</li>
</ul>
<p>First thing to note here is that preceding Zeros in Hexadecimal Notation can be ignored because they have no meaning since we are working with unsigned values here (positive only) which are assigned to Registers. For eg. <span class="code_var">0x4</span> and <span class="code_var">0x04</span> mean the same.</p>
<div class="special sp_red noteinfo">Note that bit <strong>7</strong> is <strong>MSB on extreme left</strong> and bit <strong>0</strong> is the <strong>LSB on extreme right</strong> which represents Big Endian Format. Hence bit 0 is the 1st bit from right , bit 1 is the 2nd bit from right and so on. BIT and PIN Numbers are <strong>Zero</strong>(0) indexed.</div>
<h4>Basic example code in C/C++</h4>
<p><strong>Ex. 1)</strong></p>
<p>Consider that we want to configure Pin 0 of Port 1 i.e P1.0 as Output and want to drive it HIGH. This can be done as:</p>
<pre><code class="language-cpp">
P1DIR |= BIT0; //same as (1<<0) and 0x1, Configure P0.1 as Output
P1OUT |= BIT0; //Drive Output High for P1.0
</code></pre>
<p><strong>Ex. 2)</strong></p>
<p>Making output configured Pin P1.4 LOW individually, without affecting other bits can be does as follows:</p>
<pre><code class="language-cpp">
P1DIR |= BIT4; //Configure P1.4 as Output
P1OUT &= ~BIT4; //Only P1.4 is made LOW
</code></pre>
<p><strong>Ex. 3)</strong></p>
<p>Configuring P1.4 and P1.6 as Output and Setting them HIGH together:</p>
<pre><code class="language-cpp">
P1DIR |= BIT4 | BIT6; //Config P1.4 and P1.6 as Output
P1OUT |= BIT4 | BIT6; //Drive P1.4 and P1.6 HIGHT
</code></pre>
<p><strong>Ex. 4)</strong></p>
<p>Configuring all Pins of Port 1 (P1.0 to P1.7) as Output and Setting them High:</p>
<pre><code class="language-cpp">
P1DIR = 0xFF; //Config all pins of P1 as Output
P1OUT = 0xFF; //Drive all pins HIGH
</code></pre>
<p><strong>Ex. 5)</strong></p>
<p>In this example code, we will configure Pin P1.3 as Input with internal Pullup enabled:</p>
<pre><code class="language-cpp">
P1DIR &= ~BIT3; //Config P1.3 as input (It will be anyways input after reset)
P1REN = BIT3; //Enable Pullup/down for P1.3
P1OUT = BIT3; //Select Pullup resistor for P1.3
</code></pre>
<p><strong>Ex. 6)</strong></p>
<p>We can check the current state of Input pin P1.3, configured above, as:</p>
<pre><code class="language-cpp">
if(P1IN & BIT3)
{
	//P1.3 is HIGH
}
else
{
	//P1.3 is LOW
}
</code></pre>
<p><strong>Ex. 7)</strong></p>
<p>Lets, say we have configured P1.4 as input with pullup resistor enabled and we want to continuously scan P1.4 until a LOW appears at the pin. This can be achieved as follows:</p>
<pre><code class="language-cpp">
P1DIR &= ~BIT4; //Configure P1.4 as Input
P1REN = BIT4; //Enable Pullup/down for P1.4
P1OUT = BIT4; //Select Pullup resistor for P1.4

if(..) //some condition or parent loop
{
	while( !(P1IN & BIT4) ); //wait until P1.4 is LOW (busy wait)
	/*do something after loop terminates*/
}
</code></pre>
<h2 class="shead">Real World MSP430 GPIO Examples/Programs</h2>
<p>Note: Examples(Demo Programs) given below assume default clock speeds. I have tested below programs using CCS V6.2.0 on MSP430G2231/MSP430G2211 but it will also work on MSP430G2553/MSP430G2452 and other compatible Microcontrollers.</p>
<h4>Blinky Example Code</h4>
<p>The most common example for GPIO is blinking an LED. Here we drive pin 0 of port 1 (P1.0) HIGH then LOW in a loop (Toggle). P1.0 is connected to LED1 on Launchpad Development board. We will use the intrinsic function <span class="code_var">__delay_cycles(unsigned long cycles)</span> . As evident, it generates delay by the amount of clock cycles given as argument. However, this is not the recommended method for generating delays and must be avoided. I have used it in example below just for the sake of brevity. To generate delays using Timer please check my <a href="https://www.ocfreaks.com/msp430-timer-programming-tutorial/" target="_blank">MSP430 Timer Tutorial</a>.</p>
<pre><code class="language-cpp">
#include &lt;msp430.h&gt;

int main(void)
{
	WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer to Prevent PUC Reset
	P1DIR |= BIT0; //Configure P1.0 as Output
	
	while(1)
	{
		P1OUT ^= BIT0; //Toggle P1.0 - LED Blinks
		__delay_cycles(400000);
	
		/* The above code is same as:
		P1OUT |= BIT0; //Drive P1.0 HIGH - LED1 ON
		__delay_cycles(400000);

		P1OUT &= ~BIT0; //Drive P1.0 LOW - LED1 OFF
		__delay_cycles(400000);	*/
	}
	//return 0; //normally this won't execute
}
</code></pre>
<h4>Toggle LED with Button Switch</h4>
<p>In this example program we will configure P1.3 as Input and monitor it for a LOW on the pin. P.3 is connected to Push Button Switch (S2) on the Launchpad. We will use LED2 i.e. P1.6 as output. Initially LED2 will be ON. Whenever we press the Button S2 it will toggle the LED state.</p>
<pre><code class="language-cpp">
#include &lt;msp430.h&gt;

int main(void)
{
	WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer to Prevent PUC Reset
	P1DIR &= ~BIT3 ; //explicitly making P1.3 as Input - even though by default its Input
	P1REN = BIT3; //Enable Pullup/down
	P1OUT = BIT3; //Select Pullup

	P1DIR |= BIT6; //Configuring P1.6(LED2) as Output
	P1OUT |= BIT6; //drive output HIGH initially

	while(1)
	{
		if( !(P1IN & BIT3) ) //Evaluates to True for a 'LOW' on P1.3
		{
			P1OUT ^= BIT6; //Toggle the state of P1.6
			while( !(P1IN & BIT3) ); //wait until button is released
		}
	}
	//return 0; //this won't execute normally
}

</code></pre>
<div class="special sp_blue noteinfo">Using Switches as Inputs will lead to "Bouncing" which is the spurious changes in input until the contacts of the switch have stabilized. This can be filtered out using debouncing techniques, either in Software or Hardware. Simple Hardware debouncing techniques include an RC filter with Hysteresis(Schmitt Trigger).</div>
<h4>Turn LED ON when Button is pressed else OFF</h4>
<p>Now lets modify the above example so that when the button is pressed, LED2 will glow and when released or not pressed the LED won't glow. When switch is not pressed internal pull-up resistor will force the input to a HIGH state.</p>
<pre><code class="language-cpp">
#include &lt;msp430.h&gt;

int main(void)
{
	WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer to Prevent PUC Reset
	P1DIR &= ~BIT3 ; //explicitly making P1.3 as Input - even though by default its Input
	P1REN = BIT3; //Enable Pullup/down
	P1OUT = BIT3; //Select Pullup

	P1DIR |= BIT6; //Configuring P1.6(LED2) as Output
	P1OUT &= ~BIT6; //Turn off LED2 initially
	
	while(1)
	{
		if( !(P1IN & BIT3) )
		{
			P1OUT |= BIT6; //Input LOW - turn led ON
		}
		else
		{
			P1OUT &= ~BIT6; //Input HIGH - turn led OFF
		}
	}
	
	//return 0; //normally this won't execute
}
</code></pre>
<p>The post <a href="https://www.ocfreaks.com/msp430-gpio-programming-tutorial/">MSP430 GPIO Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/msp430-gpio-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3038</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/

Page Caching using Disk: Enhanced 

Served from: www.ocfreaks.com @ 2026-03-05 03:42:12 by W3 Total Cache
-->