Forums

How to use PWM on LPC2119?

Started by swee...@hotmail.com January 24, 2008
I want to know how to use PWM.
I use Keil and LPC2119.
Please give me some example code.
and told me how to set Frequency, duty ratio and anything that
important to know when use PWM.
I'd read in datasheet and try by myself for a month but it's still
don't work.
Please help me.

Thank for advance.

An Engineer's Guide to the LPC2100 Series

>I want to know how to use PWM.
> I use Keil and LPC2119.
> Please give me some example code.

http://www.tte-systems.com/books.php

See Chapter A6.

Michael.
Thank for help me.

I want to know how to write code with keil?

what register i must to set.
and what i write in code that make output.

Example I want a output with 60kHZ and duty cycle 50%
on port PWM1.
How to write?

Thank for advance,
SweetCorn
s...@hotmail.com wrote:
> Thank for help me.
>
> I want to know how to write code with keil?
>
> what register i must to set.
> and what i write in code that make output.
>
> Example I want a output with 60kHZ and duty cycle 50%
> on port PWM1.
> How to write?

I think you'll need to look up the RTFM register. I can't
remember the exact page but if you start looking near the
beginning of the LPC2119 User manual you'll be sure to see it.

Ralph
'Bogders toolkit' here, I've tried to get a few things working for future
work as I'm learning ARM myself since dec 2007
Have a code dump, this is a get going what you can demo, with adc measured
from potentiometer and sent to the pwm and lcd. (then i fiddled and messed
with the RTC to set it using switches.)

I don't fully understand what I've done, but it works as far as I know,
since its 90% borrowed code , you will have to put the init type functions
first as i've pasted from a project, hope this helps (eg init serial, init
adc should go first)

the sections you are interested in are where I've put the xxxxxxxxs, sorry
about the other junk in the way to do with LCD etc

Gareth
/***************************************************************************
*************/
/* Target MCU : Philips ARM7-LPC2119 : X-TAL : 19.6608 MHz
(58.9824MHz) */
/* : X-TAL : 19.6608 MHz (58.9824MHz)
*/
/* Function : Example PWM2(P0.7) & ADC0(P0.27)
*/
/***************************************************************************
*************/
#include // LPC2119 MPU Register
#include // For Used Function printf
#include
#include

#define LCD_D4 0x00010000 // P1.16
#define LCD_D5 0x00020000 // P1.17
#define LCD_D6 0x00040000 // P1.18
#define LCD_D7 0x00080000 // P1.19
#define LCD_EN 0x00100000 // P1.20
#define LCD_RS 0x00200000 // P1.21
#define LCD_DATA (LCD_D4|LCD_D5|LCD_D6|LCD_D7)
#define LCD_IOALL (LCD_D4|LCD_D5|LCD_D6|LCD_D7|LCD_EN|LCD_RS)

#define lcd_rs_set() IOSET1 |= LCD_RS // RS = 1 (Select Instruction)
#define lcd_rs_clr() IOCLR1 |= LCD_RS // RS = 0 (Select Data)
#define lcd_en_set() IOSET1 |= LCD_EN // EN = 1 (Enable)
#define lcd_en_clr() IOCLR1 |= LCD_EN // EN = 0 (Disable)

#define lcd_clear() lcd_write_control(0x01) // Clear Display
#define lcd_cursor_home() lcd_write_control(0x02) // Set Cursor = 0
#define lcd_display_on() lcd_write_control(0x0E) // LCD Display Enable
#define lcd_display_off() lcd_write_control(0x08) // LCD Display Disable
#define lcd_cursor_blink() lcd_write_control(0x0F) // Set Cursor = Blink
#define lcd_cursor_on() lcd_write_control(0x0E) // Enable LCD Cursor
#define lcd_cursor_off() lcd_write_control(0x0C) // Disable LCD Cursor
#define lcd_cursor_left() lcd_write_control(0x10) // Shift Left Cursor
#define lcd_cursor_right() lcd_write_control(0x14) // Shift Right Cursor
#define lcd_display_sleft() lcd_write_control(0x18) // Shift Left Display
#define lcd_display_sright() lcd_write_control(0x1C) // Shift Right Display

void lcd_init(); // Initial LCD
void lcd_wait(); // Wait Busy LCD Complete
void lcd_out_data4(unsigned char); // Strobe 4-Bit Data to LCD
void lcd_write_byte(unsigned char); // Write 1 Byte Data to LCD
void lcd_write_control(unsigned char); // Write Instruction
void lcd_write_ascii(unsigned char); // Write LCD Display(ASCII)
void goto_cursor(unsigned char); // Set Position Cursor LCD
void lcd_print(unsigned char*); // Print Display to LCD
void delay(unsigned long int); // Delay Function

extern void initadc(unsigned int);
extern void init_serial_pwm (void); // Used Initial UART0 From
"Serial0.c"
unsigned int val, adcsnap1, adcsnap2, iopin21,iopin22,iopin23,iopin24, chan,
delay1,delay2;
char ztime[20], zadc[20];
// ADC Result (HEX)
int main(void)
{
chan=1;

CCR=0x00000001; // RTC clock on //see page 253 for dividers
PREINT= 0x00000258; //PREINT= 0x00000181; //arbitary rtc div!
PREFRAC = 0x00003144; //PREFRAC = 0x00000101;
// HOUR=0; will reset clock
// MIN=0; was IODIR1 |= 0xf03F0000;
IODIR1 = 0x003F0000; // P1.16 - P1.21 = Output
lcd_init(); // Initial LCD

init_serial_pwm(); //init the serial output to the comm port AND the pwm
registers
// PINSEL0 = 0x00000000;
IODIR0 = 0x00000018; //PART 3 set io on for all except lower bit for
serial comms and bit 10,11 for i/p
while(1) // Loop Continue
{
delay2++;
if(delay2>10){ //output to lcd
goto_cursor(0x00); // Set Cursor Line-1
sprintf(ztime,"%02u-%02u %02u:%02u:%02u",DOM,MONTH,HOUR ,MIN, SEC );
//ztime=toascii(SEC);
lcd_print(ztime); // Display LCD Line-1
goto_cursor(0x40);
//sprintf(zadc,"%01u:%01u :%04u",(adcsnap1/64),(adcsnap2/64),IOPIN0 );
// Set Cursor = Line-2
iopin24= IOPIN1&0x02000000;
iopin24=(iopin24>>25);
iopin23= IOPIN1&0x01000000;
iopin23=(iopin23>>24);
iopin22= IOPIN1&0x00800000;
iopin22=(iopin22>>23);
iopin21= IOPIN1&0x00400000;
iopin21=(iopin21>>22);

if(iopin24==0)HOUR++;
if(iopin23==0)MIN++;
sprintf(zadc,"\%u %u %u %u",iopin24,iopin23,iopin22,iopin21 );
// Set Cursor = Line-2
lcd_print(zadc);
delay2=0;
}

chan++;
if(chan>2) chan=0;
initadc(chan); //put in the adc channel for above NEXT loop

for(delay1=0;delay1<8000;delay1++);
// IOSET0 |= 0x00000008; //PART 3 set io0.4 or higher
for(delay1=0;delay1<8000;delay1++);
// IOCLR0 |= 0x00000018; //PART 3 set io
for(delay1=0;delay1<8000;delay1++);
do {
val = ADDR; // Read A/D 10-Bit Data Register
}
while ((val & 0x80000000) == 0); // Wait ADC Conversion Complete

// xxxxxxxxsxxxxxxxxsxxxxxxxxsxxxxxxxxs try here, the pwmmr2 stuff
if(chan==0) {
adcsnap1 = (val >> 6) & 0x03FF; // Shift completed ADC Result to 12
bit Integer
PWMMR2 = 0x00000000+adcsnap1;
} // Update PWM2(High Period = 0..1023 Cycle)
if(chan==1) {
adcsnap2 = (val >> 6) & 0x03FF;
PWMMR4 = 0x00000000+adcsnap2; // Update PWM4(High Period 0..1023 Cycle)
}

PWMLER = 0x00000014; // Enable PWM Match4 and 2 Latch to enable
the pwm decline

// if(chan==0) printf("\rADC0= %6.u val",adcsnap); // Display
3-Digit Result(0-3.3V)
// if(chan==1) printf(" ADC1= %6.u val",adcsnap); // Display
3-Digit Result(0-3.3V)
// if(chan==2) printf(" ADC2= %6.u val",adcsnap); // Display 3-Digit
Result(0-3.3V)
//REALTIME CLOCK
printf("\r %u:",HOUR);
printf(" %u:",MIN);
printf(" %u:",SEC);

}

}

// LCD Routines for "ET-ARM7 KIT V1.0"
// Character 16x2 4-Bit Mode Interface
// D4 = P1.16
// D5 = P1.17
// D6 = P1.18
// D7 = P1.19
// RS = P1.20
// EN = P1.21

/**************************/
/* Wait Bysy LCD Complete */
/**************************/
void lcd_wait()
{
int loopP0; // Busy Delay Time
while(loop--); // Busy Loop
}

/****************************/
/* Strobe 4-Bit Data to LCD */
/****************************/
void lcd_out_data4(unsigned char val)
{
IOCLR1 |= (LCD_DATA); // Reset 4-Bit Pin Data
IOSET1 |= (val<<16); // 0000 0000 00,EN,RS DDDD 0000 0000 0000
0000
}

/****************************/
/* Write Data 1 Byte to LCD */
/****************************/
void lcd_write_byte(unsigned char val)
{
lcd_out_data4((val>>4)&0x0F); // Strobe 4-Bit High-Nibble to LCD
lcd_en_set(); // EN = 1 = Strobe Signal
lcd_en_clr(); // EN = 0
lcd_wait(); // Wait LCD Execute Complete

lcd_out_data4((val)&0x0F); // Strobe 4-Bit Low-Nibble to LCD
lcd_en_set(); // EN = 1 = Strobe Signal
lcd_en_clr(); // EN = 0
lcd_wait(); // Wait LCD Execute Complete
}

/****************************/
/* Write Instruction to LCD */
/****************************/
void lcd_write_control(unsigned char val)
{
lcd_rs_clr(); // RS = 0 = Instruction Select
lcd_write_byte(val); // Strobe Command Byte
delay(50000); // Approx. 2mS Delay
}

/****************************/
/* Write Data(ASCII) to LCD */
/****************************/
void lcd_write_ascii(unsigned char c)
{
lcd_rs_set(); // RS = 1 = Data Select
lcd_write_byte(c); // Strobe 1 Byte to LCD
}

/*******************************/
/* Initial 4-Bit LCD Interface */
/*******************************/
void lcd_init()
{
lcd_rs_clr(); // RS = 0 = Instruction Select
lcd_en_clr(); // EN = 0
delay(50000); // wait VDD raise > 4.5V

lcd_write_control(0x33); // Initial (Set DL=1 3 Time, Reset DL=0 1
Time)
lcd_write_control(0x32);
lcd_write_control(0x28); // Function Set (DL=0 4-Bit,N=1 2
Line,F=0 5X7)
lcd_write_control(0x0C); // Display on/off Control (Entry
Display,Cursor off,Cursor not Blink)
lcd_write_control(0x06); // Entry Mode Set (I/D=1 Increment,S=0
Cursor Shift)
lcd_write_control(0x01); // Clear Display (Clear Display,Set DD
RAM Address=0)
}

/***************************/
/* Set LCD Position Cursor */
/***************************/
void goto_cursor(unsigned char i)
{
i |= 0x80; // Set DD-RAM Address Command
lcd_write_control(i);
}

/************************************/
/* Print Display Data(ASCII) to LCD */
/************************************/
void lcd_print(unsigned char* str)
{
int i;

for (i=0;i<16 && str[i]!=0;i++) // 16 Character Print
{
lcd_write_ascii(str[i]); // Print Byte to LCD
}
}

/***********************/
/* Delay Time Function */
/* 1-4294967296 */
/***********************/
void delay(unsigned long int count1)
{
while(count1 > 0) {count1--;} // Loop Decrease Counter
}

void initadc(unsigned chan)
{
ADCR &= 0x00000000; //clear all bit control

if(chan==0){
// Initial ADC0 (ADCR=0x01210601)
ADCR |= 0x00000001; // Select ADC = AIN0
}
if(chan==1){
ADCR |= 0x00000002; // Select ADC = AIN1
}
if(chan==2){
ADCR |= 0x00000004; // Select ADC = AIN2
}
//ADCR is the "control" register and maybe should be left alone more??
ADCR |= 0x00000600; // ADC Clock = VBP(PCLK) / 7
ADCR |= 0x00010000; // Busrt = 1 Conversion Continue
ADCR &= 0xFFF1FFFF; // CLKS = 000 = 10Bit : 11 Cycle Clock
Conversion
ADCR |= 0x00200000; // PDN = 1 = Active ADC Module
ADCR &= 0xFF3FFFFF; // TEST[1:0] = 00 = Normal Mode
ADCR |= 0x01000000; // START = 001 = Start Conversion Now
ADCR &= 0xF7FFFFFF; // EDGE = 0 = Conversion on Falling Edge
}

void init_serial_pwm (void)
{
//frominit befoere init serail
PINSEL1 &= 0xFF7FFFFF; // Initial ADC0 (GPIO-0.27) By Set
PINSEL1[23:22] // Select ADC0 Pin Connect P0.27
PINSEL1 |= 0x00400000; // Initial PWM2,4 (GPIO-0.7 and 0.8) By Set
PINSEL0[15:14 and..]
PINSEL0 &= 0xFFFF3FFF; //CHEK this, does clear // Select PWM2 Pin
Connect P0.7 AND P0.8
PINSEL0 |= 0x00028000; //

// xxxxxxxxsxxxxxxxxsxxxxxxxxsxxxxxxxxs try here, the pwmmr setting stufff

//pmr stuff
PWMPR = 0; // Period = 34.722 uS // 35uS Period -> 28.80KHz
Initial PWM2 = 28.8KHz (29.4912/1024(.800 KHz)
PWMPCR |= 0x00001400; // PWMENA2 = "1" = Enable PWM2 a pwm4 ....
1024+4096 )
PWMMCR = 0x00000002; // On Match0 = Reset Counter
PWMMR0 = 0x00000400; // Set PWM2 Rate(29.4912MHz/1024)
PWMMR2 = 0x00000200; // Set Default PWM2 High Pulse (0..512
Cycle)
PWMMR4 = 0x00000200; // Set Default PWM4 High Pulse (0..512
Cycle)
PWMLER = 0x00000025; // Enable Shadow Latch For Match 0,2 AND 4
PWMTCR = 0x00000002; // Reset Counter and Prescaler
PWMTCR = 0x00000009; // Enable Counter and PWM + Release Counter
>From Reset
PINSEL0 &= 0xFFFFFF00; // Reset P0.0,P0.1 Pin Config carefull here
something doing with2 tolast f needed
PINSEL0 |= 0x00000001; // Select P0.0 = TxD(UART0)
PINSEL0 |= 0x00000004; // Select P0.1 = RxD(UART0)

U0LCR &= 0xFC; // Reset Word Select(1:0)
U0LCR |= 0x03; // Data Bit = 8 Bit
U0LCR &= 0xFB; // Stop Bit = 1 Bit
U0LCR &= 0xF7; // Parity = Disable
U0LCR &= 0xBF; // Disable Break Control
U0LCR |= 0x80; // Enable Programming of Divisor Latches

// U0DLM:U0DLL = 29.4912MHz / [16 x Baud]
// = 29.4912MHz / [16 x 9600]
// = 192 = 0x00C0
U0DLM = 0x00; // Program Divisor Latch(192) for 9600 Baud
U0DLL = 0xC0;

U0LCR &= 0x7F; // Disable Programming of Divisor Latches

U0FCR |= 0x01; // FIF0 Enable
U0FCR |= 0x02; // RX FIFO Reset
U0FCR |= 0x04; // TX FIFO Reset
U0FCR &= 0x3F;
}

-----Original Message-----
From: l... [mailto:l...]On Behalf Of
Pont, Michael J.
Sent: 24 January 2008 08:59
To: l...
Subject: Re: [lpc2000] How to use PWM on LPC2119?
>I want to know how to use PWM.
> I use Keil and LPC2119.
> Please give me some example code.

http://www.tte-systems.com/books.php

See Chapter A6.

Michael.


09:58
I wasnt bothered by correct frequency, just converting ADC to a PWM level. I
did not read the right post, I accidently read reply to your post, new to
forum myself, learning how to use it!.

Use or ignore what I sent when i pasted the code, it just sets the pwm to
respond to the adc, it IS a multi channel ADC to PWM, if thats any use...
nice because you can vary brightness of couple of LED's with two
potentiometers, but I didnt use or care about the frequency.

Good luck

-----Original Message-----
From: l... [mailto:l...]On Behalf Of
s...@hotmail.com
Sent: 24 January 2008 06:53
To: l...
Subject: [lpc2000] How to use PWM on LPC2119?
I want to know how to use PWM.
I use Keil and LPC2119.
Please give me some example code.
and told me how to set Frequency, duty ratio and anything that
important to know when use PWM.
I'd read in datasheet and try by myself for a month but it's still
don't work.
Please help me.

Thank for advance.


09:58
I am using the following code at the moment (I haven't cleaned it up,
or made it generic, but I intend to make a generic version with
better doc), it is based on code from Martin Thomas' T-Clock ( http://
gandalf.arubi.uni-kl.de/avr_projects/arm_projects/ ), once the PWM
has been initialised just send a number using the set brighness
function (duty cycle as an integer), frequency is set at the top in
the PWM_FREQ macro.

You should be able to more or less drop this into your existing code
and change labels to match whatever PWM output you are using.

/*****************************************************/
#include // LPC2119 MPU Register
#include

// for PINSEL0 setup:
#define GLCDCTRL_PINMASK ((unsigned long)(0x03<<16)|(0x03<<18))
#define GLCDCTRL_PINSEL ((unsigned long)(0x02<<16)|(0x02<<18))

#define PWM_FREQ (100)
#define CPU_CORE_CLCK 58980000
#define PBSD 2
#define PCLK (CPU_CORE_CLCK/PBSD)
#define PWM_PCLK_DIV 2
#define PWMTICSperSEC (PCLK / (PWM_PCLK_DIV+1))
#define PWM_MR0INIT (unsigned long)((PWMTICSperSEC/PWM_FREQ) + 0.5)
#define PWMCR_RESET (1<<1)
#define PWMCR_ENABLE (1 << 0)

// Main Program Start Here //
void InitialisePWM(){ // Initial ADC0 (GPIO-0.27) By Set
PINSEL1[23:22]

// set function of Pins P0.8 and P0.9 as PWM4 resp. PWM6
PCB_PINSEL0 = (PCB_PINSEL0 & ~GLCDCTRL_PINMASK) | GLCDCTRL_PINSEL;

// PWM Init
PWM_TCR = PWMCR_RESET; // reset PWM counter
PWM_PR = PWM_PCLK_DIV; // set PWM Prescaler
PWM_MR0 = PWM_MR0INIT; // set Match0 (for the Single Edge PWM-
Channels)
PWM_LER |= (1<<0); // Enable PWM Match0 Latch
PWM_MCR |= (1<<1); // reset PWM Timer on PWMMR0 match
PWM_PCR &= ~((1<<4)|(1<<6)); // single edge mode for PWM4/6
PWM_PCR |= ((1<<12)|(1<<14)); // enable outputs for PWM4/6

//set the pwm rate
PWM_MR4 = (PWM_MR0INIT*50)/100L;
PWM_LER |= (1<<4); // Enable PWM Match4 Latch

PWM_TCR = PWMCR_ENABLE | (1<<3); // Counter Enable & PWM Enable

}

void SetLampBrightness(unsigned char duty_cycle)
{
if (duty_cycle>100) duty_cycle0;
PWM_MR4 = (PWM_MR0INIT*duty_cycle)/100L;
PWM_LER |= (1<<4); // Enable PWM Match4 Latch
}
As promised I have 'improved' the code I aupplied before, it is not
perfect, though this should be a bit more robust than the old code. I
have tried to keep it fairly portable.

I have not had time to set it up to configure all of the registers
automatically, though adding the few extra lines if you need them
should be very straight forward. Code below:

#include // LPC2119 MPU Register
#include

/
**********************************************************************/
/************ The sections below here can be modified for
*************/
/*************the desired frequency and to match the host
*************/
/
**********************************************************************/
//The macro below defines the desired PWM frequency in hertz
#define PWM_FREQ (100)
//This is the core clock frequency for the CPU core
#define CPU_CORE_CLCK 58980000
//Pin output divider value
#define PBSD 2
/
**********************************************************************/
/
**********************************************************************/
/
**********************************************************************/

//You shouldn't need to touch anything below here
#define PCLK (CPU_CORE_CLCK/PBSD)
#define PWM_PCLK_DIV 2
#define PWMTICSperSEC (PCLK / (PWM_PCLK_DIV+1))
#define PWM_MR0INIT (unsigned long)((PWMTICSperSEC/PWM_FREQ) + 0.5)
#define PWMCR_RESET (1<<1)
#define PWMCR_ENABLE (1 << 0)

/
***********************************************************************
The Inisitalise PWM function is intended to configure the neceasry
registers to enable a PWM driver, the number parameter refers to the
output of ineterest.
***********************************************************************/

void InitialisePWM(unsigned char number){

if (number == 1){
PCB_PINSEL0 &= 0xFFFFFFFC; //P0.0 as PWM1
PCB_PINSEL0 |= 0x00000002;
}
if (number == 2){
PCB_PINSEL0 &= 0xFFFF3FFF; //P0.7 as PWM2
PCB_PINSEL0 |= 0x00008000;
}
if (number == 3){
PCB_PINSEL0 &= 0xFFFFFFF3; //P0.1 as PWM3
PCB_PINSEL0 |= 0x00000008;
}

// PWM Init
PWM_TCR = PWMCR_RESET; // reset PWM counter
PWM_PR = PWM_PCLK_DIV; // set PWM Prescaler
PWM_MR0 = PWM_MR0INIT; // set Match0 (for the Single
Edge PWM-Channels)
PWM_LER |= (1<<0); // Enable PWM Match0 Latch
PWM_MCR |= (1<<1); // reset PWM Timer on PWMMR0
match
PWM_PCR &= ~(1< speciefied PWM
PWM_PCR |= (1<<(8+number)); // enable outputs for specified
PWM

PWM_TCR = PWMCR_ENABLE | (1<<3); // Counter Enable & PWM Enable

}

/
***********************************************************************
The set duty cycle function is intended to set the duty cycle of a
specified PWM, the first value is the duty cycle, a float is used to
allow greater control, the second value is the number of the PWM to
use.
***********************************************************************/

void SetDutyCycle(float duty_cycle, unsigned char number){

if (duty_cycle>100) duty_cycle0;

if (number==1) PWM_MR1 = (int)((PWM_MR0INIT*duty_cycle)/100L);
if (number==2) PWM_MR2 = (int)((PWM_MR0INIT*duty_cycle)/100L);
if (number==3) PWM_MR3 = (int)((PWM_MR0INIT*duty_cycle)/100L);
if (number==4) PWM_MR4 = (int)((PWM_MR0INIT*duty_cycle)/100L);
if (number==5) PWM_MR5 = (int)((PWM_MR0INIT*duty_cycle)/100L);
if (number==6) PWM_MR6 = (int)((PWM_MR0INIT*duty_cycle)/100L);

PWM_LER |= (1<
}
Thank you very much.
--- In l..., sweetcheesecorn@... wrote:
>
> Thank you very much.
>

No worries, you might want to change a few of those 'if' statements
to 'else if', I forgot to do that myself.

Good luck