<?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>mcu - OCFreaks!</title>
	<atom:link href="https://www.ocfreaks.com/tag/mcu/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.ocfreaks.com/tag/mcu/</link>
	<description>Overclocking , Gaming , Technology , Robotics &#38; DIY!</description>
	<lastBuildDate>Mon, 21 Oct 2024 07:48:44 +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>LPC2148 PWM Programming Tutorial</title>
		<link>https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/</link>
					<comments>https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/?noamp=mobile#comments</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Wed, 21 Aug 2013 16:59:29 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[lpc2148]]></category>
		<category><![CDATA[mcu]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=1462</guid>

					<description><![CDATA[<p>Introduction This Tutorial is for learning Pulse Width Modulation (PWM) programming for ARM7 based LPC214x MCUs. For this Tutorial I&#8217;ll be covering Single Edge PWM and how to use to control Motors like Servos. Also for the scope of this tutorial I won&#8217;t be going into stuff like MCU controlled Voltage Regulation using PWM since [&#8230;]</p>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/">LPC2148 PWM Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="shead"> Introduction </h2>
<p>This Tutorial is for learning <strong>Pulse Width Modulation</strong> (PWM) programming for ARM7 based <strong>LPC214x</strong> MCUs. For this Tutorial I&#8217;ll be covering Single Edge PWM and how to use to control Motors like Servos. Also for the scope of this tutorial I won&#8217;t be going into stuff like MCU controlled Voltage Regulation using PWM since I am planning a dedicated tutorial for that. I assume you are comfortable with Timers and its usage in LPC214x since PWM block is basically a Timer. I&#8217;ve posted a tutorial on Timers in LPC214x @ <a href="https://www.ocfreaks.com/lpc2148-timer-tutorial/">LPC2148 Timer Tutorial</a> &#8211; just in case if you need it.</p>
<h4> Pulse Width Modulation Basics : </h4>
<p>I&#8217;ve Posted a Beginner PWM tutorial @ <a href="https://www.ocfreaks.com/pulse-width-modulation-pwm-tutorial/">Basic PWM Tutorial</a>. If you are new to PWM please have a look there.</p>
<p>Here is Diagram that sums it up. It shows Single Edge PWM with T-ON , T-OFF &#038; Period. Duty Cycle is simply T-ON Divided by Period.</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/pwm_basics.png" alt="PWM timing showing T-on, T-off and Period" width="425px" height="180px" /></p>
<h2 class="shead"> PWM Programming in ARM7 LPC2148 </h2>
<p>LPC2148 supports 2 types of PWM :<br />
<strong>1) Single Edge PWM</strong> &#8211; Pulse starts with new Period i.e pulse is always at the beginning<br />
<strong>2) Double Edge PWM</strong> &#8211; Pulse can be anywhere within the Period</p>
<p>A PWM block , like a Timer block , has a Timer Counter and an associated Prescale Register along with Match Registers. These work exactly the same way as in the case of Timers. I&#8217;ve explained them in the introduction part of the Lpc214x Timer tutorial @ <a href="https://www.ocfreaks.com/lpc2148-timer-tutorial/">LPC2148 Timer Tutorial</a> . Match Registers 1 to 6 (except 0) are pinned on LPC214x i.e. the corresponding outputs are diverted to actual Pins on LPC214x MCU. The PWM function must be selected for these Pins to get the PWM output. These pins are :<br />
<center></p>
<table>
<tr>
<td> <strong>Output :</strong></td>
<td> PWM1</td>
<td>PWM2 </td>
<td>PWM3 </td>
<td>PWM4 </td>
<td>PWM5 </td>
<td>PWM6 </td>
</tr>
<tr>
<td><strong>Pin Name :</strong></td>
<td>P0.0 </td>
<td>P0.7 </td>
<td>P0.1 </td>
<td>P0.8 </td>
<td>P0.21 </td>
<td>P0.9 </td>
</tr>
</table>
<p></center></p>
<div class="special sp_blue noteinfo"><strong>Note :</strong> PWM1 output corresponds to PWM Match Register 1 i.e PWMMR1 , PWM2 output corresponds to PWMMR2 , and so on. Also Match Register 0 i.e PWMMR0 is NOT pinned because it is used to generate the PWM Period. Also the PWM function must be selected for the PINs mentioned above using appropriate PINSEL registers (PINSEL0 for PWM1,2,3,4,6 and PINSEL1 for PWM5).</div>
<p>In LPC214x we have 7 match registers inside the PWM block . Generally the first Match register PWMMR0 is used to generate PWM period and hence we are left with 6 Match Registers PWMMR1 to PWMMR6 to generate 6 Single Edge PWM signals or 3 Double Edge PWM signals. Double edge PWM uses 2 match registers hence we can get only 3 double edge outputs. The way this works in case of Single Edge PWM is as follows (and similarly for Double Edge):   </p>
<div class="intendb">
<ol>
<li>
Consider that our PWM Period duration is 5 milliseconds and TC increments every 1 millisecond using appropriate prescale value.
</li>
<li>Now we set the match value in PWMMR0 as 5 , <strong>Note : This period will be same for all PWM outputs!</strong></li>
<li>Then we configure PWM block such that when TC reaches value in PWMMR0 it is reset and a new Period begins.</li>
<li>Now lets say we want 2 PWM signals of Pulse widths 2ms and 4ms.</li>
<li>So .. we can use PWMMR1 and PWMMR2 to get the 2 outputs. For that we set PWMMR1 = 2 and PWMMR2 = 4.
</li>
<li>Then , Everytime a new period starts the Pin corresponding to PWMMR1 and PWMMR2 will be set High by default.</li>
<li>And .. Whenever the value in TC reaches PWMMR1 and PWMMR2 its output will be set to low respectively.</li>
<li>Their outputs will remain low until the next Period starts after which their outputs again become high .. hence giving us Single Edge PWM.</li>
</ol>
</div>
<p>This can be shown in the diagram below:</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/embedded/common/lpc_pwm_timing_diagram.png" alt="ARM LPC Microcontroller PWM Module Timing Diagram" width="525px" height="325px" /></p>
<div class="highlight">
<strong>PWM Rules: </strong>The LPC214x User Manual mentions Rules for using Single Edge and Double Edge PWM on page 261 . The Rules for Single Edged PWM are as :</p>
<ul>
<li>1) All single edged PWM outputs will go high at the beginning of a PWM cycle unless their match value is 0.</li>
<li>2) Each PWM output will go low when its match value is reached. Note : If no match occurs i.e Match value is greater than Period then the output will remain high!</li>
</ul>
</div>
<p>For Double Edge Rules you can refer the User Manual <strong>Pg. 261</strong>.</p>
<div class="special sp_red noteinfo"><strong>Note 1:</strong> The last 6 Match Registers i.e PWMMR1 to PWMMR6 have an associated PIN from which we get the PWM outputs. The PWM block controls the output of these pins depending on the value in its corresponding Match Register. For Single Edged PWM these Pins are set to High by default when a new Period starts i.e when TC is reset as per the PWM Rules given above.</p>
<p><strong>Note 2:</strong> Note that Here we are storing the width of the Pulse in the Match Register. We can also change the width of the pulse by changing the value in the corresponding Match register using a special register called Latch Enable Register which is used to control the way Match Registers get updated. I&#8217;ll explain this shortly. First Lets see all the Registers in PWM Block in LPC2148.</div>
<div class="highlight">
Now lets have a look at some important Registers :</p>
<h4>1) PWMTCR : PWM Timer Control Register</h4>
<p>This register is used to control the Timer Counter inside the PWM block. Only Bits: 0, 1  &#038; 3 are used rest are reserverd.</p>
<ul>
<li><strong>Bit 0 :</strong> This bit is used to Enable/Disable Counting. When 1 both PWM Timer counter and PWM Prescale counter are enabled. When 0 both are disabled.</li>
<li><strong>Bit 1 :</strong> This bit is used to Reset both Timer and Prescale counter inside the PWM block. When set to 1 it will reset both of them (at next edge of PCLK).</li>
<li><strong>Bit 3 :</strong> This is used to enable the PWM mode i.e the PWM outputs.</li>
<li>Other Bits : Reserved.</li>
</ul>
<h4>2) PWMPR : PWM Prescale Register</h4>
<p>PWMPR is used to control the resolution of the PWM outputs. The Timer Counter(TC) will increment every PWMPR+1 Peripheral Clock Cycles (PCLK).</p>
<h4>3) PWMMR0 &#8211; PWMMR6 : Match Registers</h4>
<p>These are the seven Match registers as explained above which contain <strong>Pulse Width Values i.e the Number of PWMTC Ticks</strong>.</p>
<h4>4) PWMMCR : PWM Match Control Registers</h4>
<p>The PWM Match Control Register is used to specify what operations can be done when the value in a particular Match register equals the value in TC. For each Match Register we have 3 options : Either generate an Interrupt , or Reset the TC , or Stop .. which stops the counters and disables PWM. Hence this register is divided into group of 3 bits. The first 3 bits are for Match Register 0 i.e PWMMR0 , next 3 for PWMMR1 , and so on :</p>
<ul>
<li><strong>1) Bit 0 :</strong> Interrupt on PWMMR0 Match &#8211; If set to 1 then it will generate an Interrupt else disable if set to 0.</li>
<li>
<strong>2) Bit 1 :</strong> Reset on PWMMR0 Match &#8211; If set to 1 it will reset the Timer Counter i.e PWMTC else disabled if set to 0.
</li>
<li><strong>3) Bit 2 :</strong> Stop on PWMMR0 Match &#8211; If this bit is set 1 then both PWMTC and PWMPC will be stopped and will also make Bit 0 in PWMTCR to 0 which in turn will disable the Counters.</li>
<li><strong>*)</strong> Similarly {Bits 3,4,5} for PWMMR1 , {Bits 6,7,8} for PWMMR2 , {Bits 9,10,11} for PWMMR3 ,{Bits 12,13,14} for PWMMR4 ,{Bits 15,16,17} for PWMMR5 , {Bits 18,19,20} for PWMMR6.</li>
</ul>
<h4>5) PWMIR : PWM Interrupt Register </h4>
<p>If an interrupt is generated by any of the Match Register then the corresponding bit in PWMIR will be set high. Writing a 1 to the corresponding location will clear that interrupt. Here :</p>
<ul>
<li><strong>1) Bits 0,1,2,3</strong> are for PWMMR0, PWMMR1, PWMMR2, PWMMR3 respectively and </li>
<li><strong>2) Bits 8,9,10</strong> are for PWMMR4 , PWMMR5 , PWMMR6 respectively. Other bits are reserved.</li>
</ul>
<h4>6) PWMLER : Latch Enable Register </h4>
<p>The PWM Latch Enable Register is used to control the way Match Registers are updated when PWM generation is active. When PWM mode is active and we apply new values to the Match Registers the new values won&#8217;t get applied immediately. Instead what happens is that the value is written to a &#8220;Shadow Register&#8221; .. it can be thought of as a duplicate Match Register. Each Match Register has a corresponding Shadow Register. The value in this Shadow Register is transferred to the actual Match Register when :</p>
<div class="intendb"><strong>1)</strong> PWMTC is reset (i.e at the beginning of the next period) ,<br />
<strong>2)</strong> And the corresponding Bit in PWMLER is 1.
</div>
<p>Hence only when these 2 conditions are satisfied the value is copied to Match Register. Bit &#8216;x&#8217; in PWMLER corresponds to match Register &#8216;x&#8217;. I.e Bit 0 is for PWMMR0 , Bit 1 for PWMMR1 , .. and so on. Using PWMLER will be covered in the examples section.</p>
<h4>7) PWMPCR : PWM Control Register </h4>
<p>This register is used for Selecting between Single Edged &#038; Double Edged outputs and also to Enable/Disable the 6 PWM outputs which go to their corresponding Pins. </p>
<ul style="margin-bottom:0px;">
<li>1) <strong>Bits 2 to 6</strong> are used to select between Single or Double Edge mode for PWM 2,3,4,5,6 outputs.
<div class="intendb">1) <strong>Bit 2 :</strong> If set to 1 then PWM2(i.e the one corresponding to PWMMR2) output is double edged else if set 0 then its Single Edged.<br />
2) Similarly <strong>{Bits 3,4,5,6}</strong> for PWM3 , PWM4 , PWM5 , PWM6 respectively.</div>
</li>
<li>2)<strong> Bits 9 to 14</strong> are used to Enable/Disable PWM outputs
<div class="intendb">1) <strong>Bit 9 : </strong>If set to 1 then PWM1 output is enabled , else disabled if set to 0.<br />
2)Similarly <strong>{Bit 10,11,12,13,14}</strong> for PWM2 , PWM3 , PWM4 , PWM5 , PWM6 respectively.</div>
</li>
</ul>
</div>
<h2 class="shead">Configuring and Initializing PWM:</h2>
<p>Configuring PWM is very much similar to Configuring Timer except, additionally, we need to enable the outputs and select PWM functions for the corresponding PIN on which output will be available. But first we need to do some basic Math Calculations for defining the Period time , the resolution using a prescaler value and then Pulse Widths. For this First we need to define the resolution of out PWM signal. Here the PWM resolution which I mean is the minimum increment that can use to increase or decrease the pulse width. More smaller the increment more fine will be the resolution. This resolution is defined using  an appropriate Prescale Value. The calculation for Prescale is the same which I had shown in the Timer Tutorial .. but here it is once again :</p>
<div class="special sp_blue noteinfo">
<h4>LPC2148 PWM Prescaler (PWMPR) Calculations:</h4>
<p>The delay or time required for &#8216;Y&#8217; clock cycles of PCLK at ‘X’ MHz is given by :</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/pwm/delay.png" alt="Delay for Y Clock Cycles at X Mhz" class="aligncenter" width="210px" height="65px"/></p>
<p>When we take PR into consideration we get Y = PR+1. Now , consider that PCLK is running at 60Mhz then X=60. Hence if we use Y=60 i.e PR=59 then we get a delay of exact 1 micro-second(s). </p>
<p>So with PR=59 and PCLK @ 60Mhz our formula reduces to :</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/pwm/delay_1us.png" alt="1us Delay at 60Mhz" class="aligncenter" width="290px" height="65px"/></p>
<p>Similarly when we set Y=60000 i.e PR = 59999 the delay will be 1 milli-second(s) :</p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/pwm/delay_1ms_b.png" alt="1ms Delay at 60Mhz" class="aligncenter" width="310px" height="65px"/></p>
<p>This delay which is defined using Prescale will be the delay required for <strong>TC to increment by 1</strong> i.e <strong>TC will increment every &#8216;PR+1&#8217; &#8220;Peripheral&#8221; Clock Cycles (PCLK)</strong>.
</div>
<div class="highlight">
Now , After we&#8217;ve worked out the resolution we want .. we can now Set and Initialize the PWM device as per the following steps :</p>
<ol>
<li>Select the PWM function for the PIN on which you need the PWM output using PINSEL0/1 register.</li>
<li>Select Single Edge or Double Edge Mode using PWMPCR. By default its Single Edge Mode.</li>
<li>Assign the Calculated value to PR.</li>
<li>Set the Value for PWM Period in PWMMR0.</li>
<li>Set the Values for other Match Registers i.e the Pulse Widths.</li>
<li>
Set appropriate bit values in PWMMCR .. like for e.g. resetting PWMTC for PWMMR0 match and optionally generate interrupts if required
</li>
<li>Set Latch Enable Bits for the Match Registers that you&#8217;ve used. This is important!</li>
<li>Then Enable PWM outputs using PWMPCR.</li>
<li>Now Reset PWM Timer using PWMTCR.</li>
<li>Finally .. Enable Timer Counter and PWM Mode using PWMTCR.</li>
</ol>
<p><strong>Example :</strong></p>
<pre><code class="language-cpp">
PINSEL0 = ... ; // Select PWM Function for used Pins
PWMPCR = ... ; // Select PWM type - By default its Single Edged
PWMPR = ... ; //assign calculated PR value 
PWMMR0 = ... ; // Assign Period Duration
PWMMRx = ... ; // Assign pulse duration i.e widths for other Match Regs.. x=1 to 6
PWMMCR = (1<<1) | ... ; // Reset PWMTC on PWMMR0 match &#038; Other conditions
PWMLER = (1<<1) | ... ; // update MR0 and other Match Registers
PWMPCR = ... ; // enable PWM outputs as required
PWMTCR = (1<<1) ; //Reset PWM TC &#038; PR

//Now , the final moment - enable everything
PWMTCR = (1<<0) | (1<<3); // enable counters and PWM Mode
//Done!
</code></pre>
</div>
<h4>Updating Match Registers i.e the Pulse Width</h4>
<p>Once PWM is initialized then you can update any of the Match Registers at anytime using PWMLER. This can be done as follows :</p>
<pre><code class="language-cpp">
PWMMR1 = 50; // Update Pulse Width
PWMLER = (1<<1); // set the corresponding bit to 1</code></pre>
<p>When you want to update Multiple Match Registers then this can be done as follows :</p>
<pre><code class="language-cpp">
PWMMR1 = 50;
PWMMR2 = 68;
PWMMR3 = 20;

PWMLER = (1<<1) | (1<<2) | (1<<3); // Update Latch Enable bit for all MRs together</code></pre>
<h2 class="shead"> Some Real World Examples with sample code</h2>
<p>I'll cover 2 examples using Single Edge PWM. These will be:<br />
<strong>1) Controlling RC Servo<br />
2) LED Dimming</strong></p>
<p>To stay within the scope of this article I'm not including a bit involved stuff like "RC Servo Speed Control" and "DC Motor Speed Control". I guess I'll do it in a separate article.</p>
<div class="special sp_blue notestar">Before we get into the Examples , I would like to mention a few words about a function named "<strong>initClocks()</strong>" which I've been using in all examples. This function basically configures PLL0 and Sets up CPU Clock at 60Mhz and Peripheral Clock also at 60Mhz. You can find the the source for initClocks() in the Attached Project Files. If you are not sure about how to configure PPL0 in LPC214x , you can find a simple tutorial @ <a href="https://www.ocfreaks.com/lpc214x-pll-tutorial-for-cpu-and-peripheral-clock/"><br />
LPC214x PLL Tutorial for CPU and Peripheral Clock</a>.</div>
<h4>Example #1) Simple RC Servo Control Using PWM : </h4>
<p>Here we will use PWM1 output from Pin P0.0 to control a RC Servo Motor. We will also be using 4 tactile switches to bring the Servo at 4 different positions. P0.1 , P0.2 , P0.3 , P0.4 will be used to take the input. One end of the tactile switches will be connected to each of these Pins and other end will be connected to ground. Here we'll also require external 5V-6V source to drive the servo. Servos can work with 3.3v voltage levels for input PWM signal , hence we just need to connect the MCU PWM Output to Servo PWM Input wire. The setup is as shown in the schematic below :</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/pwm/sch-ex1-pwm.png" /></p>
<p>When the user will press P0.1 the Pulse width will be 1ms , and similarly when the user presses P0.2 , P0.3 , P0.4 the Pulse Width will change to 1.25ms , 1.5ms and 1.75ms respectively and hence Servo will change its position correspondingly. </p>
<p><strong>Source for Example 1:</strong></p>
<pre><code class="language-cpp">
/*
(C) Umang Gajera | Power_user_EX - www.ocfreaks.com 2011-13.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded

LPC2148 PWM Tutorial Example 1 - RC Servo Control using PWM.
License : GPL.
*/
#include &lt;lpc214x.h&gt;

#define PLOCK 0x00000400
#define PWMPRESCALE 60   //60 PCLK cycles to increment TC by 1 i.e 1 Micro-second 

void initPWM(void);
void initClocks(void);

int main(void)
{
	initClocks(); //Initialize CPU and Peripheral Clocks @ 60Mhz
	initPWM(); //Initialize PWM

    //IO0DIR = 0x1; This is not needed!
    //Also by default all pins are configured as Inputs after MCU Reset.
   
    while(1)
    {
		if( !((IO0PIN) & (1<<1)) ) // Check P0.1
		{
			PWMMR1 = 1000;
			PWMLER = (1<<1); //Update Latch Enable bit for PWMMR1
		}
		else if( !((IO0PIN) &#038; (1<<2)) ) // Check P0.2
		{
			PWMMR1 = 1250;
			PWMLER = (1<<1);
		}
		else if( !((IO0PIN) &#038; (1<<3)) ) // Check P0.3
		{
			PWMMR1 = 1500;
			PWMLER = (1<<1);
		}
		else if( !((IO0PIN) &#038; (1<<4)) ) // Check P0.4
		{
			PWMMR1 = 1750;
			PWMLER = (1<<1);
		}
    }
    //return 0; //normally this wont execute ever
}

void initPWM(void)
{
	/*Assuming that PLL0 has been setup with CCLK = 60Mhz and PCLK also = 60Mhz.*/
	/*This is a per the Setup &#038; Init Sequence given in the tutorial*/

	PINSEL0 = (1<<1); // Select PWM1 output for Pin0.0
	PWMPCR = 0x0; //Select Single Edge PWM - by default its single Edged so this line can be removed
	PWMPR = PWMPRESCALE-1; // 1 micro-second resolution
	PWMMR0 = 20000; // 20ms = 20k us - period duration
	PWMMR1 = 1000; // 1ms - pulse duration i.e width
	PWMMCR = (1<<1); // Reset PWMTC on PWMMR0 match
	PWMLER = (1<<1) | (1<<0); // update MR0 and MR1
	PWMPCR = (1<<9); // enable PWM output
	PWMTCR = (1<<1) ; //Reset PWM TC &#038; PR

	//Now , the final moment - enable everything
	PWMTCR = (1<<0) | (1<<3); // enable counters and PWM Mode

	//PWM Generation goes active now!!
	//Now you can get the PWM output at Pin P0.0!
}
</code></pre>
<div class="highlight"><strong>Download Project Source for Example #1 @</strong> <a href='https://www.ocfreaks.com/imgs/_downloads/lpc2148/OCFreaks.com_LPC214x_PWM_Tutorial_Example_2.zip'>LPC214x PWM Tutorial Example 1.zip</a> [Successfully tested on Keil UV4.70a] </div>
<h4>Example #2) LED Dimming using PWM :</h4>
<p>The basic Setup here is same as in Example 1 except that here we replace Servo by a LED and we dont need external 5V source along with slightly modified Program. Here we'll just need to connect the anode of LED to P0.0 and cathode to GND. In this example will use a period of 10ms. In this case the Pulse Widths Corresponding to the Switches connected to P0.1/2/3/4 will be 2.5ms/5ms/7.5ms/10ms respectively. As the Pulse Width Increases LED will keep on getting Brighter and the reverse will happen if Pulse Width is decreased.</p>
<p><strong>Source for Example 2: </strong></p>
<pre><code class="language-cpp">
/*
(C) Umang Gajera | Power_user_EX - www.ocfreaks.com 2011-13.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded

LPC2148 PWM Tutorial Example 2 - LED Dimming using PWM.
License : GPL.
*/
#include &lt;lpc214x.h&gt;

#define PLOCK 0x00000400
#define PWMPRESCALE 60   //60 PCLK cycles to increment TC by 1 i.e 1 Micro-second 

void initPWM(void);
void initClocks(void);

int main(void)
{
	initClocks(); //Initialize CPU and Peripheral Clocks @ 60Mhz
	initPWM(); //Initialize PWM

    //IO0DIR = 0x1; This is not needed!
    //Also by default all pins are configured as Inputs after MCU Reset.
   
    while(1)
    {
		if( !((IO0PIN) & (1<<1)) ) // Check P0.1
		{
			PWMMR1 = 2500; //T-ON=25% , Hence 25% Bright
			PWMLER = (1<<1); //Update Latch Enable bit for PWMMR1
		}
		else if( !((IO0PIN) &#038; (1<<2)) ) // Check P0.2
		{
			PWMMR1 = 5000; //50% Bright
			PWMLER = (1<<1);
		}
		else if( !((IO0PIN) &#038; (1<<3)) ) // Check P0.3
		{
			PWMMR1 = 7500; //75% Bright
			PWMLER = (1<<1);
		}
		else if( !((IO0PIN) &#038; (1<<4)) ) // Check P0.4
		{
			PWMMR1 = 10000; //100% Bright
			PWMLER = (1<<1);
		}
    }
    //return 0; //normally this wont execute ever
}

void initPWM(void)
{
	/*Assuming that PLL0 has been setup with CCLK = 60Mhz and PCLK also = 60Mhz.*/
	/*This is a per the Setup &#038; Init Sequence given in the tutorial*/

	PINSEL0 = (1<<1); // Select PWM1 output for Pin0.0
	PWMPCR = 0x0; //Select Single Edge PWM - by default its single Edged so this line can be removed
	PWMPR = PWMPRESCALE-1; // 1 micro-second resolution
	PWMMR0 = 10000; // 10ms period duration
	PWMMR1 = 2500; // 2.5ms - pulse duration i.e width (Brigtness level)
	PWMMCR = (1<<1); // Reset PWMTC on PWMMR0 match
	PWMLER = (1<<1) | (1<<0); // update MR0 and MR1
	PWMPCR = (1<<9); // enable PWM output
	PWMTCR = (1<<1) ; //Reset PWM TC &#038; PR

	//Now , the final moment - enable everything
	PWMTCR = (1<<0) | (1<<3); // enable counters and PWM Mode

	//PWM Generation goes active now - LED must be 25% Bright after Reset!!
	//Now you can get the PWM output at Pin P0.0!
}
</code></pre>
<div class="highlight"><strong>Download Project Source for Example #2 @</strong> <a href='https://www.ocfreaks.com/imgs/_downloads/lpc2148/OCFreaks.com_LPC214x_PWM_Tutorial_Example_2.zip'>LPC214x PWM Tutorial Example 2.zip</a> [Successfully tested on Keil UV4.70a] </div>
<p><span class="shead"><span class="sheadin">More stuff using PWM</span></span><br />
I've had 2 requests for Sine Wave generation using PWM , <strike>which I'll be doing soon</strike> which you can find here : <a href="https://www.ocfreaks.com/sine-wave-generator-using-pwm-lpc2148-microcontroller-tutorial/">Sine Wave Generator using PWM with LPC2148 Microcontroller Tutorial</a>. I might also cover MCU controlled voltage Regulation along with double egde PWM 🙂</p>
<p><strong>Please do leave your Article Requests , Suggestions & Comments. </strong></p>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/">LPC2148 PWM Programming Tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc2148-pwm-programming-tutorial/feed/</wfw:commentRss>
			<slash:comments>12</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1462</post-id>	</item>
		<item>
		<title>LPC2148 Keil uVision ARM7 Interrupt Problem and Issue fix</title>
		<link>https://www.ocfreaks.com/lpc2148-keil-uvision-arm7-interrupt-problem-issue-fix/</link>
					<comments>https://www.ocfreaks.com/lpc2148-keil-uvision-arm7-interrupt-problem-issue-fix/?noamp=mobile#comments</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Thu, 28 Mar 2013 06:19:08 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[lpc2148]]></category>
		<category><![CDATA[mcu]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=1069</guid>

					<description><![CDATA[<p>Many guys including me have been facing a problem with KEIL uVision4 with ARM7 based microcontrollers like LPC2148 where the Interrupts or IRQs wont execute even if the code is correct .. but now I&#8217;ve found a simple trick to make the interrupts work. Even I have wasted a long time trying to figure out [&#8230;]</p>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-keil-uvision-arm7-interrupt-problem-issue-fix/">LPC2148 Keil uVision ARM7 Interrupt Problem and Issue fix</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Many guys including me have been facing a problem with KEIL uVision4 with ARM7 based microcontrollers like LPC2148 where the Interrupts or IRQs wont execute even if the code is correct .. but now I&#8217;ve found a simple trick to make the interrupts work. Even I have wasted a long time trying to figure out what the heck was going wrong with KEIL4 or ARM7 Vectored Interrupt controller . This problem was not there with KEIL3 and the code would work flawless.</p>
<div class="highlight">To make your interrupts fire in KEIL4 for you ARM7 based microcontrollers .. all you need to do is : &#8216;Check&#8217; a Checkbox in Target options Under the Linker Tab and you are Done! I don&#8217;t know why .. but KEIL4 doesn&#8217;t do this automatically when you create new project.</div>
<p><strong>Step 1 &#8211; Click Target Options which will open a new Window. Next click on the &#8216;Linker&#8217; Tab:<br />
</strong><br />
<img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc2148-interrupt-issue-solved/1.jpg" /></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc2148-interrupt-issue-solved/2.jpg" /></p>
<p><strong>Step 2 &#8211; Check the very first checkbox called &#8220;Use Memory layout from Target Dialog&#8221;:</strong></p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/lpc2148-interrupt-issue-solved/3.jpg" /></p>
<p>Now , rebuild your target and run the simulation. Interrupts must fire now.</p>
<div class="snippet_darkblue">For those having similar problem on Crossworks for ARM / Yagarto or any other GNU based ARM toolchain a fix is @ <a href="https://forum.sparkfun.com/viewtopic.php?p=66975">Here</a></div>
<p><strong>Whether this helped you or not please let me know in your comments.</strong></p>
<p>The post <a href="https://www.ocfreaks.com/lpc2148-keil-uvision-arm7-interrupt-problem-issue-fix/">LPC2148 Keil uVision ARM7 Interrupt Problem and Issue fix</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc2148-keil-uvision-arm7-interrupt-problem-issue-fix/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1069</post-id>	</item>
		<item>
		<title>Interfacing 16X2 LCD with LPC2148 tutorial</title>
		<link>https://www.ocfreaks.com/interfacing-16x2-lcd-with-lpc2148-tutorial/</link>
					<comments>https://www.ocfreaks.com/interfacing-16x2-lcd-with-lpc2148-tutorial/?noamp=mobile#comments</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Wed, 19 Dec 2012 14:54:01 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[featured]]></category>
		<category><![CDATA[lpc2148]]></category>
		<category><![CDATA[mcu]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=734</guid>

					<description><![CDATA[<p>On special request of our readers today we are posting a new tutorial for interfacing HD44780U / KS0066U based 16x2 LCD Module with LPC2148 microcontroller.</p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-16x2-lcd-with-lpc2148-tutorial/">Interfacing 16X2 LCD with LPC2148 tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><!-- img class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/s/lpc2148-lcd-cover.jpg" /--></p>
<p><span class="shead"><span class="sheadin">Introduction</span></span><br />
Interfacing a 16X2 or 16X4 LCD module with a 3.3V MCU is not same as interfacing with MCUs like AVR which operate on 5Volts. As per request by some of the readers of previous articles on lpc2148 this article is on Interfacing a 5V LCD Module with LPC2148 MCU and in general for any ARM or 3.3V MCU .</p>
<p><strong>Whats next?</strong> : A simple Library for LCD interfacing with LPC214x and LPC176x MCUs. And more tutorials on Timer , PWM , UART .. for lpc214x , lpc176x.</p>
<p>For this article I&#8217;ve used the readily available Chinese 16X2 LCD Module :<strong> JHD-162A</strong>. The Data sheet for JHD-162A 16X2 LCD Module is located at : http://www.egochina.net.cn/eBay/Download/JHD162A.pdf I would strongly suggest that you keep that datasheet open when reading this article to avoid any sort of confusion.</p>
<p>Before Starting the Tutorial , as a motivation , I would like to show the final outcome of this tutorial. The pic below shows the LPC2148 development board interfaced with JHD162A LCD Module via 2x HCF4050B ICs. I&#8217;ll come to HCF4050B IC shortly .. at the moment lets get started with the  basics.</p>
<p><a href="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/lpc2148-lcd-1.png"><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/s/lpc2148-lcd-1.jpg" /></a></p>
<p><span class="shead"><span class="sheadin">16X2 LCD Basics :</span></span></p>
<p>This particular chinese LCD i.e JHD162A has KS0066U controller or similar to the famous HD44780U. It Consists of 2 Rows with 16 Characters on each. It has a 16 pin Interface. Operates on 5V and has LED backlight. Works in 2 Modes :</p>
<ul>
<li>1) <strong>Instruction Mode :</strong> Used for initializing and configuring LCD before we can use it &#038; during operation.</li>
<li>2) <strong>Data Mode :</strong> Displays the respective characters for codes supplied to it via Data Pins.</li>
</ul>
<p>Standard Pinout is as follows :</p>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/jhd162a-lcd-pinout.jpg" /></p>
<p>To keep things simple lets group the pins into 3 :<br />
<b>1) Power Pins :</b> Pin 1,2,3,15,16<br />
<b>2) Control Pins :</b> Pin 4,5,6<br />
<b>3) Data Pins :</b> Pin 7 to 14</p>
<div class="highlight">
<strong>Now lets see some of the important pins before we actually start writing programs for LCD:</strong></p>
<ul>
<li><strong>Contrast Voltage (VEE) :</strong> Instead of using a trim pot just connect a 1K resistor to VEE in series and ground it. That gives the best contrast of what I&#8217;ve seen.</li>
<p></p>
<li><strong>RS &#8211; short for Register select (Control Pin) :</strong> Used to switch been Instruction and Data Mode. RS = High for Instruction Mode and RS = Low for Data mode.</li>
<p></p>
<li><strong>R/W &#8211; Read or Write (Control Pin):</strong> R/W = High for Read Mode and R/W = Low for Write. Since we are going to use Write Mode only we will permanently ground it using a pull-down resistor of 4.7K Ohms. Caution : If you are planning to use Read Mode with 3.3V MCUs you&#8217;ll need a Bi-directional level shifter which can shift 5V to 3.3V and Vice-Versa.
</li>
<p></p>
<li><strong>Enable (Control Pin) :</strong> This is similar to a trigger pin. Each Data/Instruction is executed by the LCD module only when a pulse is applied to Enable pin. More specifically the it is executed at the falling edge of the pulse.</li>
</ul>
</div>
<p>If you want to know the fundamentals and internal operation of LCD Modules I would recommend visiting these links :</p>
<ul>
<li><a href="http://lcd-linux.sourceforge.net/pdfdocs/lcd1.pdf" target="_blank" rel="noopener">http://lcd-linux.sourceforge.net/pdfdocs/lcd1.pdf</a></li>
<li><a href="http://lcd-linux.sourceforge.net/pdfdocs/lcd2.pdf" target="_blank" rel="noopener">http://lcd-linux.sourceforge.net/pdfdocs/lcd2.pdf</a></li>
<li><a href="http://www.8051projects.net/lcd-interfacing/" target="_blank" rel="noopener">http://www.8051projects.net/lcd-interfacing/</a> (Covers a lot of basics .. I found it really helpful.)
</li>
</ul>
<p><span class="shead"><span class="sheadin">Interfacing 5V LCD Module with lpc214x:</span></span></p>
<p>5V LCD wont operate on 3.3V and also since lpc214x runs on 3.3V and 5Volts might fuse some of its GPIO pin we are gonna need a level shifter or translator that can shift 3.3Volts to 5Volts for LCD Module to be safe. Vikram Sharma M. has successfully interfaced JHD162A with MSP430 MCU using CD4050B IC as explained in his post @ <a href="http://msharmavikram.wordpress.com/2012/08/14/3-mistakes-of-lcd-with-msp430-solved/" target="_blank" rel="noopener">http://msharmavikram.wordpress.com/2012/08/14/3-mistakes-of-lcd-with-msp430-solved/</a> .</p>
<p>Some of the buffers / level shifters than can be used are : SN74AHC244N , SN74AC241N , CD74AC244E , CD4050B , etc.. out of which CD4050B is readily available. I purchased a few HCF4050 which is same as CD4050B except it is manufactured by ST Microelectronics and not Texas Instruments.</p>
<p>HCF4050B is a non-inverting Hex Buffer. In our case we&#8217;ll be needing 2 of them at minimum since we are going to use 8+2=10 pins from MCU which need to be shifted to 5Volts. There are going to be 8 Data pins and 2 control pins connected from MCU to the LCD Module using 2x HCF4050B.</p>
<div class="snippet_darkred">NOTE : As far as possible use the 1st eight consecutive pins(at any cost!) from any port of the MCU as Data Pins which will make sending character data or commands(Instructions) to LCD very easy. For e.g. in our case we will use P0.0 to P0.7 as data pins and P1.16 as RS pin and P1.17 as Enable pin.</div>
<p>Connections from lpc214x to LCD module will be as shown below. I&#8217;ve also made a PCB for the schematic if bread-board is not your cup of tea.(Frankly , since I was running out of time I did it using a bread-board. If some one is having any problems with PCB please let me know.)</p>
<p><a href="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/lcd-arm-interface.png"><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/s/lcd-arm-interface.jpg" /></a></p>
<div class="snippet_darkblue">
<strong>Pin Connections from MCU->HFC4050B->LCD:</strong></p>
<p>1)Pin Connections from MCU to HCF4050B ICs :<br />
IC1 : P1.16->Pin3 , P1.17->Pin5 , P0.0->Pin7 , P0.1->Pin9 , P0.2->Pin11 , P0.3->Pin14<br />
IC2 : P0.4->Pin3 , P0.5->Pin5 , P0.6->Pin7 , P0.7->Pin9 (Pins 11,14 of IC2 are NC)</p>
<p>2)Pin Connections from HCF4050B to LCD Module :<br />
IC1 : Pin2->RS , Pin4->Enable , Pin6->DB0 , Pin10->DB1 , Pin12->DB2 , Pin15->DB3<br />
IC2 : Pin2->DB4 , Pin4->DB5 , Pin6->DB6 , Pin10->DB7 (Pin 12,15 of IC2 are NC)
</p></div>
<p><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/pcb.png" /></p>
<h4>Download links to PCB pdf and Eagle 6.2+ (Schematic+Board) Design Files:</h4>
<p>1) <a href="https://www.ocfreaks.com/forums/attachment.php?attachmentid=1573&#038;d=1355926263">lcd_interface_arm_mcu_PCB-pdf.rar</a><br />
2) <a href="https://www.ocfreaks.com/forums/attachment.php?attachmentid=1574&amp;d=1355926264">lcd_interface_arm_mcu-EAGLE-6.2+design-files.rar</a> </p>
<p><b>Components required at bare minimum :</b></p>
<ul>
<li>LPC214x Development board</li>
<li>16X2 LCD Module</li>
<li>2x HFC4050B or CD4050B</li>
<li>5V Supply for LCD </li>
<li>Resistors : 1x 1K , 1x 4.4K , 1x 47 Ohms</li>
<li>Bread-Board / Self-made PCB</li>
<li>Berg Strips , Jumper wires</li>
</ul>
<div class="snippet_darkred"><strong>NOTE :</strong> You need to connect the &#8216;GND&#8217; from MCU Board to &#8216;LCD&#8217;s GND&#8217; else its not gonna work. Diode D1 and Decoupling Capacitors C1 &#038; C2 are optional. D1 can be replaced by a short and C1,C2 can be ignored.</div>
<div class="vspacer_20px"> </div>
<p><span class="shead"><span class="sheadin">Initializing LCD Module :</span></span></p>
<p>After you have cross-checked all your connections from MCU to HFC4050 to LCD Module its time now to Display text on LCD. But before that we need to initialize the LCD properly. Also NOTE that : as per the Datasheet &#8211; before initializing LCD we need to wait for a minimum time of about 15ms after the input voltage supply is stable and >4.5Volts. </p>
<p>The 1st thing required for this is that RS must be held LOW and Enable also LOW in the beginning. Now we must supply some commands using the Data Pins to LCD. But this command wont be executed until we supply a pulse to Enable Pin. After supplying the command we make enable High and then Low after a short delay(i.e a Pulse) and the command is executed.</p>
<p>Codes for various instructions can be obtained from below table : (Refer to page 12 of the Datasheet)</p>
<p><a href="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/lcd-instruction-set.jpg"><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/s/lcd-instruction-set.jpg" /></a></p>
<div class="highlight">For beginners we are only interested in following commands (which are also executed in given order during initialization):</p>
<ol>
<li>Function Set</li>
<li>
Display Switch</li>
<li>
Input Set</li>
<li>Screen Clear Command</li>
<li>DDRAM AD Set &#8211; Resposition Cursor Command</li>
</ol>
<ul>
<li>In our case we are going to use 8Bit Mode with 2Rows and 5&#215;10 Font style which gives Function set as 0x3C.</li>
<li>
Next we issue Display On , Cursor On , Blink On which gives Display Switch as 0x0F.</li>
<li>
Next we select Increment Mode which gives Input Set as 0x06.</li>
<li>
Now we clear the screen and set cursor at Home which gives Screen Clear as 0x01.</li>
<li>
Also the command to reposition the cursor at Home at anytime is 0x80 and to reposition it at the 1st column of the second row is 0xC0.</li>
</ul>
</div>
<p><b>To cut-short or in simple words:</b> We need to supply 5 commands in given order to the Data Pins with a small amount of delay in between to initialize the LCD properly. These commands are : 0x3C , 0x0F , 0x06 , 0x01 , 0x80(actually not required). Now since we have used the the 1st eight pins of port 0 on lpc214x we can directly assign these values to the IO0PIN register. Note that Bit 0 i.e LSB in IO0PIN is towards extreme right and the bit number increases as we move towards the left approaching the MSB. Also since we have connected P0.0 to Data Bit 0 pin , P0.1 to Data bit 1 and so on &#8230; we have a one to one consecutive mapping between them MCU pins and LCD Data pins.</p>
<div class="snippet_darkblue"> <b>NOTE:</b> During Initialization , issuing 0x80 command to reposition the cursor at home will be of no use since it would already be at Home after issuing Screen Clear Command. Also we need to Supply a Pulse to Enable after issuing each command and wait for a short while for the LCD controller to process it. Datasheet says a delay of 40us is required at minimum. But even a delay of 1ms wont hurt us to be on the safer side.</div>
<div class="snippet_darkyellow"><b><br />
Correct Sequence for Initializing LCD module (8 Bit Interface) is as given :</p>
<ol>
<li>After LCD Module is powered on and MCU boots wait for 20ms (Specifically >15ms)</li>
<p></p>
<li>Now make RS and Enable LOW making sure that R/W is permanently grounded.</li>
<p></p>
<li>Issue Function set command &#8211; 0x3C and Pulse Enable (wait for >40us after pulsing).</li>
<p></p>
<li>Issue Display Switch &#8211; 0x0F and Pulse Enable (wait for >40us after pulsing).</li>
<p></p>
<li>Issue Input Set &#8211; 0x06 and Pulse Enable (wait for >40us after pulsing).</li>
<p></p>
<li>Issue Screen Clear &#8211; 0x01 and Pulse Enable (wait for >1.64ms after pulsing).</li>
<p></p>
<li>Issue DDRAM AD Set &#8211; 0x80 and Pulse Enable (wait for >40us after pulsing).</li>
</ol>
<p></b></div>
<p>Now LCD is ready for Printing!</p>
<p>After Initializing the LCD you would see a Cursor Blinking at in 1st column at row 1 :</p>
<p><a href="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/2.jpg"><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/s/2.jpg" /></a></p>
<p><span class="shead"><span class="sheadin">Printing Characters on LCD Module :</span></span></p>
<p>Now that we have initialized LCD correctly its time to send some characters. For this we enter into Data Mode by making RS High. After that any number / code applied to Data pins will be converted into corresponding Character and displayed. The codes for the characters are ASCII Codes given by the font table as show below :</p>
<p><a href="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/lcd-font-table.jpg"><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/s/lcd-font-table.jpg" /></a></p>
<p>Hence to print a character on LCD we just need to apply the 8bit ASCII code to Data pins. This can be done easily by type casting the character into an integer (which is done automatically by the compiler &#8211; but we are doing it here explicitly). Refer to Page 14 of datasheet for font table.</p>
<p>Now , after printing 16 characters you might wanna print more characters in 2nd Row. This is done by entering into Instruction Mode by holding RS=LOW and giving command 0xC0 which repositions the cursor at 2nd Row &#038; 1st column. Needless to say that we need to again give a Pulse on Enable pin to process it. After that we put RS to high and get back in Data mode.</p>
<div class="snippet_darkblue"><b>Note on Repositioning the Cursor :</b> As we have seen , the command for repositioning the cursor at home is 0x80. Think of 0x80 as the base address of Display Data Ram(DDRAM). Hence 0x80 will set cursor at 1st Row, 1st Column. If you add 0x01 to 0x80 the cursor will go to 2nd column in 1st row. Likewise if you add 0x0F to 0x80 you&#8217;ll end up at 1st row , last column. Similar to this the base address for 2nd Row is 0x40 and not 0x10! 0x10 is the base address of 3rd row and 0x50 is base address for 4th row in the case of 16&#215;4 LCD Modules. So to position the cursor at 2nd row, 1st column we must add 0x40 to 0x80 which gives 0x80+0x40=0xC0. Hence after giving command &#8216;0xC0&#8217; cursor comes down to 2nd row &#038; 1st col.</p>
<p>More on DDRAM and CGROM @ <a href="http://www.8051projects.net/lcd-interfacing/basics.php" target="_blank" rel="noopener">http://www.8051projects.net/lcd-interfacing/basics.php</a>
</div>
<div class="vspacer_25px"> </div>
<p><span class="shead"><span class="sheadin">Programs for Lpc2148 to print Characters on LCD module :</span></span></p>
<p>1st Let me explain a few functions that I&#8217;ve made in the programs below:</p>
<ul>
<li><strong>initLCD() :</strong> Initializes the LCD.</li>
<li><strong>enable() : </strong>To generate a pulse on Enable pin.</li>
<li><strong>LCD_Cmd(int) :</strong> To issue LCD commands.</li>
<li><strong>LCD_WriteChar(char) : </strong>Print a Single Character.</li>
<li><strong>LCD_WriteString(string) : </strong>Print a String.</li>
<li><strong>delay() :</strong>Generate required delay.(For program1 Only!)</li>
<li><strong>delayMS(int) :</strong> Generate specificed delay.(For program2 Only!)</li>
</ul>
<h4>Program #1 : Basic Program without precise Timing &#038; no PLL setup.</h4>
<pre><code class="language-cpp">
/*
 (C) OCFreaks! | Umang Gajera 2012-13.
 More Embedded tutorials @ www.ocfreaks.com/cat/embedded
 >>Program for Interfacing 16X2 LCD Module with LPC2148
*/

#include &lt;lpc214x.h&gt;

/*
 Connections from LPC2148 to LCD Module:
 P0.0 to P0.7 used as Data bits.
 P1.16 connected to pin4 i.e. RS	- Command / Data
 P1.17 connected to pin6 i.e. E - Enable
 Pin5 of LCD Module i.e. 'R/W' connected to ground
*/	

void initLCD(void);
void enable(void);
void LCD_WriteChar(char c);
void LCD_WriteString(char * string);
void LCD_Cmd(unsigned int cmd);
void delay(void);


int main(void)
{
	initLCD(); //LCD Now intialized and ready to Print!
	LCD_WriteString(".: Welcome to :.");
	LCD_Cmd(0x80 + 0x40); //Come to 2nd Row
	LCD_WriteString("www.OCFreaks.com");
	while(1); // Loop forever	 
	return 0; //This won't execute :P
}

void initLCD(void)
{
	IO0DIR = 0xFF; //P0.0 to P0.7 configured as Output - Using 8 Bit mode
	IO1DIR |= (1<<16) | (1<<17); //P1.16 and P1.17 configured as Output - Control Pins
	IO0PIN = 0x0; //Reset Port0 to 0.	
	IO1PIN = 0x0; //Reset Port1 to 0 - Which also makes RS and Enable LOW.

	//LCD Initialization Sequence Now starts
	delay(); //Initial Delay
	LCD_Cmd(0x3C); //Function Set Command : 8 Bit Mode , 2 Rows , 5x10 Font Style
	LCD_Cmd(0x0F); //Display Switch Command : Display on , Cursor on , Blink on
	LCD_Cmd(0x06); //Input Set : Increment Mode 
	LCD_Cmd(0x01); //Screen Clear Command , Cursor at Home
	LCD_Cmd(0x80); //Not required the 1st time but needed to reposition the cursor at home after Clearing Screen 
	//Done!
}

void enable(void)
{
	delay();
	IO1PIN |=  (1<<17);//Enable=High
	delay();
	IO1PIN &#038;= ~(1<<17);//Enable=Low
	delay();
}

void LCD_WriteChar(char c)
{
	IO1PIN |= (1<<16); //Switch to Data Mode
	IO0PIN = (int) c; //Supply Character Code
	enable(); //Pulse Enable to process it
}

void LCD_WriteString(char * string)
{
	int c=0;
	while (string[c]!='\0')
	{
		LCD_WriteChar(string[c]);
		c++;
	}
}
		
void LCD_Cmd(unsigned int cmd)
{
	IO1PIN = 0x0; //Enter Instruction Mode
	IO0PIN = cmd; //Supply Instruction/Command Code
	enable(); //Pulse Enable to process it
}

void delay(void)
{
	int i=0,x=0;
	for(i=0; i<19999; i++){ x++; }
}
</code></pre>
<h4>Program #2 : Program with PLL* setup and precise Timing**. (Xtal=12Mhz , CCLK=60Mhz)</h4>
<p>*PLL tutorial for LPC2148 @ <a href="https://www.ocfreaks.com/lpc214x-pll-tutorial-for-cpu-and-peripheral-clock/" target="_blank" rel="noopener">https://www.ocfreaks.com/lpc214x-pll-tutorial-for-cpu-and-peripheral-clock/</a><br />
**Tutorial on Timer for LPC2148 @ <a href="https://www.ocfreaks.com/lpc2148-timer-tutorial/" target="_blank" rel="noopener">https://www.ocfreaks.com/lpc2148-timer-tutorial/</a></p>
<pre><code class="language-cpp">
/*
 (C) OCFreaks! | Umang Gajera 2012-13.
 More Embedded tutorials @ www.ocfreaks.com/cat/embedded
 >>Program2 for Interfacing 16X2 LCD Module with LPC2148
 >>using Timer0 and CPU @ 60Mhz
*/


#include &lt;lpc214x.h&gt;

/*
 XTAL Freq=12 Mhz , CCLK=60Mhz , PCLK=60Mhz
 Using common delay of 2ms for all operations
 	
 Connections from LPC2148 to LCD Module:
 P0.0 to P0.7 used as Data bits.
 P1.16 connected to pin4 i.e. RS    - Command / Data
 P1.17 connected to pin6 i.e. E - Enable
 Pin5 of LCD Module i.e. 'R/W' connected to ground
*/ 

#define PLOCK 0x00000400

void initLCD(void);
void enable(void);
void LCD_WriteChar(char c);
void LCD_WriteString(char * string);
void LCD_Cmd(unsigned int cmd);
void delayMS(unsigned int milliseconds);

void setupPLL0(void);
void feedSeq(void);
void connectPLL0(void);


int main(void)
{
    setupPLL0();
    feedSeq(); //sequence for locking PLL to desired freq.
    connectPLL0();
    feedSeq(); //sequence for connecting the PLL as system clock
   
    //SysClock is now ticking @ 60Mhz!
       
    VPBDIV = 0x01; // PCLK is same as CCLK i.e 60Mhz
    
	//PLL0 Now configured!

	initLCD(); //LCD Now intialized and ready to Print!
    LCD_WriteString(".: Welcome to :.");
    LCD_Cmd(0x80 + 0x40); //Come to 2nd Row
    LCD_WriteString("www.OCFreaks.com");
    while(1); // Loop forever    
    return 0; //This won't execute :P
}

void initLCD(void)
{
    IO0DIR = 0xFF; //P0.0 to P0.7 configured as Output - Using 8 Bit mode
    IO1DIR |= (1<<16) | (1<<17); //P1.16 and P1.17 configured as Output - Control Pins
    IO0PIN = 0x0; //Reset Port0 to 0.  
    IO1PIN = 0x0; //Reset Port1 to 0 - Which also makes RS and Enable LOW.

    //LCD Initialization Sequence Now starts
    delayMS(20); //Initial Delay
    LCD_Cmd(0x3C); //Function Set Command : 8 Bit Mode , 2 Rows , 5x10 Font Style
    LCD_Cmd(0x0F); //Display Switch Command : Display on , Cursor on , Blink on
    LCD_Cmd(0x06); //Input Set : Increment Mode
    LCD_Cmd(0x01); //Screen Clear Command , Cursor at Home
    LCD_Cmd(0x80); //Not required the 1st time but needed to reposition the cursor at home after Clearing Screen
    //Done!
}

void enable(void)
{
    //Using common delay of 2ms
	delayMS(2);
    IO1PIN |=  (1<<17);//Enable=High
    delayMS(2);
    IO1PIN &#038;= ~(1<<17);//Enable=Low
    delayMS(2);
}

void LCD_WriteChar(char c)
{
    IO1PIN |= (1<<16); //Switch to Data Mode
    IO0PIN = (int) c; //Supply Character Code
    enable(); //Pulse Enable to process it
}

void LCD_WriteString(char * string)
{
    int c=0;
    while (string[c]!='\0')
    {
        LCD_WriteChar(string[c]);
        c++;
    }
}
       
void LCD_Cmd(unsigned int cmd)
{
    IO1PIN = 0x0; //Enter Instruction Mode
    IO0PIN = cmd; //Supply Instruction/Command Code
    enable(); //Pulse Enable to process it
}

void delayMS(unsigned int milliseconds)
{
//Timers will be explained in detail in the very next tutorial @ www.ocfreaks.com/cat/embedded/
	
	T0IR = 0;
	T0CTCR = 0;
	T0PR = 60000; //60000 clock cycles @60Mhz = 1 mS
	T0PC = 0;
	T0TC = 0;
	T0TCR = 0x01; //enable timer
	
	//wait until timer counter reaches the desired dela1y	
	while(T0TC < milliseconds);
	
	T0TCR = 0x00; //disable timer
}

//---------PLL Related Functions :---------------

void setupPLL0(void)
{
    PLL0CON = 0x01; // PPLE=1 &#038; PPLC=0 so it will be enabled
                    // but not connected after FEED sequence
    PLL0CFG = 0x24; // set the multipler to 5 (i.e actually 4)
                    // i.e 12x5 = 60 Mhz (M - 1 = 4)!!!
                    // Set P=2 since we want FCCO in range!!!
                    // So , Assign PSEL =01 in PLL0CFG as per the table.
}

void feedSeq(void)
{
    PLL0FEED = 0xAA;
    PLL0FEED = 0x55;
}

void connectPLL0(void)
{
    // check whether PLL has locked on to the  desired freq by reading the lock bit
    // in the PPL0STAT register

    while( !( PLL0STAT &#038; PLOCK ));

    // now enable(again) and connect
    PLL0CON = 0x03;
}
</code></pre>
<p>Output after flashing any of the above code to MCU (Successfully Tested on Lpc2148 and Lpc1768) :</p>
<p><a href="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/lpc2148-lcd-2.jpg"><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/s/lpc2148-lcd-2.jpg" /></a></p>
<h4>Download Links to Source Code using KEIL UV4 Project IDE :</h4>
<p>1) Program #1 : <a href="https://www.ocfreaks.com/imgs/_downloads/lpc2148/OCFreaks.com_LPC2148_LCD_Interfacing.rar">OCFreaks.com_LPC2148_LCD_Interfacing.rar</a><br />
2) Program #2 : <a href="https://www.ocfreaks.com/imgs/_downloads/lpc2148/OCFreaks.com_LPC2148_LCD_Interfacing_precise.rar">OCFreaks.com_LPC2148_LCD_Interfacing_precise.rar</a></p>
<p><span class="shead"><span class="sheadin">Silence please : 2 LCDs were Harmed in the making</span></span><br />
While working on this article 2 of my Green LCDs were damaged. One got completely useless and other got partially damaged. In any case both of them are useless now.</p>
<p>LCD #1 : Display completely gone kaput..</p>
<p><a href="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/6.jpg"><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/s/6.jpg" /></a></p>
<p>LCD #2 : Display partially gone kaput..</p>
<p><a href="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/5.jpg"><img decoding="async" class="aligncenter" src="https://www.ocfreaks.com/imgs/arm-lpc-mcu-lcd-interfacing/s/5.jpg" /></a></p>
<p>The post <a href="https://www.ocfreaks.com/interfacing-16x2-lcd-with-lpc2148-tutorial/">Interfacing 16X2 LCD with LPC2148 tutorial</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/interfacing-16x2-lcd-with-lpc2148-tutorial/feed/</wfw:commentRss>
			<slash:comments>12</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">734</post-id>	</item>
		<item>
		<title>LPC214x PLL Tutorial for Cpu and Peripheral Clock</title>
		<link>https://www.ocfreaks.com/lpc214x-pll-tutorial-for-cpu-and-peripheral-clock/</link>
					<comments>https://www.ocfreaks.com/lpc214x-pll-tutorial-for-cpu-and-peripheral-clock/?noamp=mobile#comments</comments>
		
		<dc:creator><![CDATA[Umang Gajera]]></dc:creator>
		<pubDate>Wed, 07 Nov 2012 19:08:03 +0000</pubDate>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[LPC2148 Tutorials]]></category>
		<category><![CDATA[lpc2148]]></category>
		<category><![CDATA[mcu]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">http://www.ocfreaks.com/?p=496</guid>

					<description><![CDATA[<p>Introduction PLL stands for Phase Locked Loop and is used to generate clock pulse given a reference clock input which is generally from a crystal oscillator(or XTAL). Configuring and using PLL in lpc124x MCUs is pretty simple and straight forward. Lpc214x MCUs have 2 PLL blocks viz. PPL0 and PLL1. PLL0 is used to generate [&#8230;]</p>
<p>The post <a href="https://www.ocfreaks.com/lpc214x-pll-tutorial-for-cpu-and-peripheral-clock/">LPC214x PLL Tutorial for Cpu and Peripheral Clock</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span class="shead"><span class="sheadin">Introduction</span></span></p>
<p>PLL stands for Phase Locked Loop and is used to generate clock pulse given a reference clock input which is generally from a crystal oscillator(or XTAL). Configuring and using PLL in lpc124x MCUs is pretty simple and straight forward.</p>
<p>Lpc214x MCUs have 2 PLL blocks viz. PPL0 and PLL1. PLL0 is used to generate the System Clock which goes to CPU and on-chip peripherals while PPL1 is strictly for USB. PLL interrupts are only available for PLL0 and not for PLL1. Input clock to both the PLLs must be between 10Mhz to 25Mhz strictly. This input clock is multiplied with a suitable multiplier and scaled accordingly. But here we have a upper limit of 60Mhz which is the maximum frequency of operation for lpc214x MCUs. PLLs also contain CCOs i.e current controlled oscillators which we are not much concerned about &#8230; atleast in the case of lpc214x MCUs. CCOs operate in range of 156Mhz to 320Mhz and there is also a divider to force CCOs to remain in their range.</p>
<p><span class="shead"><span class="sheadin">Basics</span></span></p>
<p>Lets define some symbols which are used in Datasheet and also which I&#8217;ll be using in this tutorial :</p>
<p><center></p>
<table>
<tr>
<td><strong>FOSC </strong> </td>
<td>=> frequency from the crystal oscillator(XTAL)/external clock</td>
</tr>
<tr>
<td><strong>FCCO </strong> </td>
<td>=> frequency of the PLL Current Controlled Oscillator(CCO)</td>
</tr>
<tr>
<td><strong>CCLK </strong> </td>
<td>=> PLL output frequency (CPU Clock)</td>
</tr>
<tr>
<td><strong>M </strong></td>
<td>=> PLL Multiplier value from the MSEL bits in the PLLCFG register</td>
</tr>
<tr>
<td><strong>P </strong> </td>
<td>=> PLL Divider value from the PSEL bits in the PLLCFG register</td>
</tr>
<tr>
<td><strong>PCLK </strong> </td>
<td>=> Peripheral Clock which is derived from CCLK</td>
</tr>
</table>
<p>[Table 1]<br />
</center></p>
<div class="special sp_blue noteinfo">
<span class="font_15px"><strong>Now , PLL output clock is given by the formula:</strong></span></p>
<ul>
<li><strong>CCLK = M x FOSC</strong> </ul>
</li>
<ul>
=or= </ul>
<ul>
<li><strong>CCLK = FCCO / (2 x P)</strong></ul>
</li>
<p><span class="font_15px"><strong>CCO output clock is given by:</strong></span></p>
<ul>
<li><strong>FCCO = CCLK x 2 x P </strong></ul>
</li>
<ul>
=or= </ul>
<ul>
<li><strong>FCCO = FOSC x M x 2 x P</strong></ul>
</li>
</div>
<p><strong><br />
Note from Datasheet:</strong></p>
<div class="special sp_blue noteinfo">The PLL inputs and settings must meet the following:</p>
<ul style="margin-bottom:0px">
<li>FOSC is in the range of 10 MHz to 25 MHz.</li>
<li>CCLK is in the range of 10 MHz to Fmax (the maximum allowed frequency for the microcontroller &#8211; determined by the system microcontroller is embedded in).</li>
<li>FCCO is in the range of 156 MHz to 320 MHz.</li>
</ul>
</div>
<div class="vspacer_25px"> </div>
<p><span class="shead"><span class="sheadin">Setting-up and using PLL</span></span></p>
<p>Here we&#8217;ll be focusing on PLL0. We&#8217;ll see PLL1 some other day since its not required at this moment. Explaining the internal working of PLLs and CCOs in detail is not in the scope of this tutorial. Here we are just concerned about its usage rather than knowing its internals. To play with PLLs we are given a Multiplier and a Divider which decide the output frequency/clock form PLL block. But we must play cautiously with PLLs since the CPU and other MCU peripherals operate on the clock provided buy it. So if PLL is deliberately or accidentally miss-configured the MCU may go nuts! Miss configuring it deliberately is the sole responsibility of the user and not us ;P Now .. to handle the accident part .. we have a got a FEED Sequence which needs to be issued whenever we wanna configure PPL. You can visualize this by imagining PLL to be enclosed in a safe or a locker. To access PLL we need to have a key to open the safe in order to use or configure it. The key here is the &#8216;Feed Sequence&#8217;. Feed Sequence is nothing but assignment of 2 particular &#8216;fixed&#8217; values to a register related to the PLL block. This register is called &#8216;PLL0FEED&#8217;. And those fixed values are 0xAA and 0x55 are &#8216;in order&#8217;!. Hence the code for feed sequence must be :</p>
<pre><code class="language-cpp">
PLL0FEED = 0xAA;
PLL0FEED = 0x55;
</code></pre>
<p>Now , lets see the other PLL Registers we can use:</p>
<div class="highlight">
<strong><span class="font_15px">1)PLLxCON:</span>(x= PLL block 0 or 1)</strong> This is the PLL Control register used to enable and &#8216;connect&#8217; the PLL. The first bit is used to &#8216;Enable&#8217; PLL. The second bit is used to &#8216;Connect&#8217; the PLL.</p>
<div class="special sp_cyan noteinfo"><strong>Note #1:</strong> Initially when the MCU boots-up it uses its internal RC Oscillator as clock source. When the PLL is setup and enabled we must switch from internal RC Oscillator to the PLL&#8217;s output clock. This is referred to as &#8216;Connecting&#8217; the PLL. PLL is only connected when both &#8216;Enable&#8217; and &#8216;Connect&#8217; bits are 1 and a valid feed sequence is applied.</div>
<p><strong><span class="font_15px">2)PLLxCGF:</span></strong> The multiplier and divider values are stored in this register. The 1st 5 bits (called <strong>MSEL</strong>) are used to store the Multiplier(M). Next 2 bits i.e 5,6 (called <strong>PSEL</strong>) are used to store the value of the Divider(P).</p>
<p><strong><span class="font_15px">3)PLLxSTAT:</span></strong> This is a read only register and contains current status of PLL enable , connect , M and P values. You can read more about the bits in datasheet &#8211; page #37. We are more interested in the 10th bit of PLLxSTAT since it contains the lock status. When we setup and enable the PLL it takes a while for PLL to latch on the target frequency. After PLL has latched or locked to target frequency this bit becomes 1. Only after this we can connect PLL to the CPU. Hence , we need to wait for PLL to lock on to target frequency.
</div>
<div class="special sp_red noteinfo">The <strong>Order</strong> of setting up PLLs is <strong>strictly</strong> as follows :</p>
<ol style="margin-bottom:0px">
<li>Setup PLL</li>
<li>Apply Feed Sequence</li>
<li>
Wait for PLL to lock and then Connect PLL</li>
<li>Apply Feed Sequence</li>
</ol>
</div>
<p><strong>Note that we have to apply Feed Sequence strictly as mentioned above.</strong></p>
<p><span class="shead"><span class="sheadin">Calculating PLL0 Settings</span></span></p>
<div class="highlight">
<ol style="margin-bottom:0px">
<li>Select the CPU Frequency. This selection may be based many factors and end application. On Chip peripheral devices may be running on a lower clock than the processor.</li>
<li>Choose an oscillator frequency (FOSC). CCLK must be the whole (non-fractional) multiple of FOSC. Which leaves us with a few values of Xtal for the selected CPU frequency (CCLK).</li>
<li>Calculate the value of M to configure the MSEL bits. M = CCLK / FOSC. M must be in the range of 1 to 32. The value written to the MSEL bits in PLLCFG is M &#8211; 1.</li>
<li>Find a value for P to configure the PSEL bits, such that FCCO is within its defined frequency limits. FCCO is calculated using the equation given above. P must have one of the values 1, 2, 4, or 8.</li>
</ol>
</div>
<p>Values of PSEL for P are :<br />
<center></p>
<table>
<tr>
<td><strong> P </strong></td>
<td><strong>Value</strong>(binary) in <strong>PSEL Bit(5,6)</strong></td>
</tr>
<tr>
<td> 1 </td>
<td> 00 </td>
</tr>
<tr>
<td> 2 </td>
<td> 01 </td>
</tr>
<tr>
<td> 4 </td>
<td> 10 </td>
</tr>
<tr>
<td> 8 </td>
<td> 11 </td>
</tr>
</table>
<p>[Table 2]<br />
</center></p>
<p>Now , Since there is no point in running the MCU at lower speeds than 60Mhz (except in some situations) ill put a table giving values for M and P for different crystal frequencies i.e FOSC. </p>
<div class="special sp_yellow noteinfo"><strong>The Value of P depends on the selection of CCLK. So , for CCLK=60Mhz we get P=2 from the equation P = FCCO/(2xCCLK).<br />
<em><br />
How did I get that ? Here&#8217;s how :</em> Since we want FCCO in range 156Mhz to 320Mhz first substitute FCCO = 156 and we get P = 1.3. Now substituting the maximum value for FCCO i.e 320Mhz we get P = 2.67. Now , P must be an integer between 1.3 and 2.67. So we will use P=2.</strong> </div>
<p><center></p>
<table>
<tr>
<td><strong>FOSC</strong></td>
<td><strong>M</strong></td>
<td><strong>Value in MSEL (M-1)</strong></td>
<td><strong>P</strong></td>
<td><strong>Value in PSEL</strong></td>
<td><strong>Final Value in PLL0CFG</strong></td>
</tr>
<tr>
<td>5Mhz</td>
<td>12</td>
<td>11 = [0xB]</td>
<td>2</td>
<td>01</td>
<td>0x2B</td>
</tr>
<tr>
<td>10Mhz</td>
<td>6</td>
<td>5 = [0x5]</td>
<td>2</td>
<td>01</td>
<td>0x25</td>
</tr>
<tr>
<td>12Mhz</td>
<td>5</td>
<td>4 = [0x4]</td>
<td>2</td>
<td>01</td>
<td>0x24</td>
</tr>
<tr>
<td>15Mhz</td>
<td>4</td>
<td>3 = [0x3]</td>
<td>2</td>
<td>01</td>
<td>0x23</td>
</tr>
<tr>
<td>20Mhz</td>
<td>3</td>
<td>2 = [0x2]</td>
<td>2</td>
<td>01</td>
<td>0x22</td>
</tr>
</table>
<p>[Table 3]<br />
</center></p>
<p><!-- 

<h4>#2) PLL1 for USB</h4>



[Will be added shortly]
--><br />
<span class="shead"><span class="sheadin">Setting-up Peripheral Clock (PCLK)</span></span></p>
<p>The Peripheral Clock i.e. PCLK is derived from CPU Clock i.e. CCLK. The APB Divider decides the operating frequency of PCLK. The input to APB Divider is CCLK and output is PCLK. </p>
<p><img decoding="async" src="https://www.ocfreaks.com/imgs/lpc2148-tutorial/pll/hm1.png" width=610px class="aligncenter" /></p>
<p>By Default PCLK runs at 1/4th the speed of CCLK. To control APB Divider we have a register called <strong>VPBDIV</strong>. The value in VPBDIV controls the division of CCLK to generate PCLK as shown below:<br />
<center></p>
<table>
<tr>
<td>VPBDIV=<strong>0x00;</strong></td>
<td>APB bus clock (PCLK) is one fourth of the processor clock (CCLK)</p>
<tr>
<td>VPBDIV=<strong>0x01;</strong></td>
<td>APB bus clock (PCLK) is the same as the processor clock (CCLK)</p>
<tr>
<td>VPBDIV=<strong>0x02;</strong></td>
<td>APB bus clock (PCLK) is one half of the processor clock (CCLK)</p>
<tr>
<td>VPBDIV=<strong>0x03;</strong></td>
<td>Reserved. If this value is written to the APBDIV register, it has no effect (the previous setting is retained).<br />
</table>
<p></center></p>
<p><span class="shead"><span class="sheadin">Example</span></span></p>
<p>Now , lets make it more simple and write a code to run MCU @ 60Mhz (CCLK,PCLK) when input clock from Crystal is 12Mhz (which is.. in most cases). If your development board has crystal of another frequency , then in that case , you need to change the values for multiplier(<strong>M</strong>) and divider(<strong>P</strong>) accordingly as per the equations.</p>
<div class="special sp_blue notewarning"><strong>Note #2:</strong> For PLLCFG register we have to use a value of <strong>(M-1)</strong> for MSEL Bits where M is the value obtained from the equations. For e.g. if we want to use <strong>M=5</strong> from the equation then we have to apply a value of <strong>(M-1)=(5-1)=4</strong> to the register. Similarly we have to use a specific value for PSEL bits as mentioned in table 2. Hence for <strong>P=1</strong> we have to assign <strong>00</strong> to PSEL , for <strong>P=2</strong> we have to assign <strong>01</strong> to PSEL and so on..</div>
<pre><code class="language-cpp">
/*
(c) Umang Gajera - www.ocfreaks.com
This e.g. shows how to set up , initialize 
and connect PLL0 to get CCLK & PCLK @ 60Mhz
Assumption : Input freq of 12MHZ from Crystal.
*/

#define PLOCK 0x400 //10th bit = 1

#include &lt;lpc214x.h&gt;

void setupPLL0(void);
void feedSeq(void);
void connectPLL0(void);
		
int main(void)
{
	setupPLL0();
	feedSeq(); //sequence for locking PLL to desired freq.
	connectPLL0();
	feedSeq(); //sequence for connecting the PLL as system clock

	//SysClock is now ticking @ 60Mhz!
	   
	VPBDIV = 0x01; // PCLK is same as CCLK i.e 60Mhz

	while(1);

	//return 0;
	}

void setupPLL0(void)
{
	PLL0CON = 0x01; // PPLE=1 & PPLC=0 so it will be enabled 
					// but not connected after FEED sequence
	PLL0CFG = 0x24; // set the multipler to 5 (i.e actually 4) 
					// i.e 12x5 = 60 Mhz (M - 1 = 4)!!!
					// Set P=2 since we want FCCO in range!!!
					// So , Assign PSEL =01 in PLL0CFG as per the table.
}

void feedSeq(void)
{
	PLL0FEED = 0xAA;
	PLL0FEED = 0x55;
}

void connectPLL0(void)
{
	// check whether PLL has locked on to the  desired freq by reading the lock bit
	// in the PPL0STAT register

	while( !( PLL0STAT & PLOCK ));

	// now enable(again) and connect
	PLL0CON = 0x03;
} 
</code></pre>
<p>The post <a href="https://www.ocfreaks.com/lpc214x-pll-tutorial-for-cpu-and-peripheral-clock/">LPC214x PLL Tutorial for Cpu and Peripheral Clock</a> appeared first on <a href="https://www.ocfreaks.com">OCFreaks!</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.ocfreaks.com/lpc214x-pll-tutorial-for-cpu-and-peripheral-clock/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">496</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 21:36:14 by W3 Total Cache
-->