After translating it to Oberon I made a simple test and monitored the results from my Logic Scope.
For IR transmission you need a 36 to 40 khz clocksignal with a Duty cycle of about 25%. This means the Clock will be high (1) for 25% of the time and low (0) for 75% of the cycle time.
Code: Select all
MODULE PWM;
(*****************************************************************************
* pwm.c: PWM module file for NXP LPC23xx/24xx Family Microprocessors
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.07.20 ver 1.00 Preliminary version, first Release
* 2011-10-15 W. Nijland Oberon-07 Port
******************************************************************************)
IMPORT SYSTEM, LPC := LPC2378, VIC;
CONST
LER0Enable=0; LER1Enable=1;
TCRCounterEnable=0; TCRCounterReset=1; TCRPWMEnable=3;
PCRPWMENA1=9; (* enable physical port output *)
VAR
MatchCounter1* : INTEGER;
(******************************************************************************
** Function name: PWM.Set
**
** Descriptions: PWM cycle setup
**
** parameters: PWM cycle = (Fpclk / pwm-freq), and duty percentage
** Returned value: None
**
******************************************************************************)
PROCEDURE ResetCounters*;
BEGIN
MatchCounter1 := 0;
END ResetCounters;
(******************************************************************************
** Function name: PWM.Set
**
** Descriptions: PWM cycle setup
**
** parameters: PWM cycle = (Fpclk / pwm-freq), and duty percentage
** Returned value: None
**
******************************************************************************)
PROCEDURE Set*(CONST cycle, percentage : INTEGER);
BEGIN
SYSTEM.PUT(LPC.PWM1MR0, cycle); (* set PWM cycle *)
SYSTEM.PUT(LPC.PWM1MR1, cycle * percentage DIV 100);
(* The LER will be cleared when the Match 0 takes place, in order to
load and execute the new value of match registers, all the PWMLERs need to be reloaded.
PWM latch enabled *)
SYSTEM.PUT(LPC.PWM1LER, {LER0Enable, LER1Enable})
END Set;
(******************************************************************************
** Function name: PWM.Start
**
** Descriptions: Enable PWM by setting the PCR, PTCR registers
**
** parameters: None
** Returned value: None
**
******************************************************************************)
PROCEDURE Start*;
VAR
bits : SET;
BEGIN
(* All single edge, all enable *)
SYSTEM.PUT(LPC.PWM1PCR, {PCRPWMENA1});
(* Timer Control Register *)
SYSTEM.PUT(LPC.PWM1TCR, {TCRCounterEnable, TCRPWMEnable})
END Start;
(******************************************************************************
** Function name: PWM.Stop
**
** Descriptions: Stop all PWM channels
**
** parameters: None
** Returned value: None
**
******************************************************************************)
PROCEDURE Stop*;
BEGIN
SYSTEM.PUT(LPC.PWM1PCR, {});
SYSTEM.PUT(LPC.PWM1TCR, {}); (* Stop all PWMs *)
END Stop;
(******************************************************************************
** Function name: PWM Handler
**
** Descriptions: PWM1 interrupt handler
** For now, it only deals with PWM1 match 0
** parameters: None
** Returned value: None
**
******************************************************************************)
PROCEDURE IntHandler[4];
CONST
IRPWMMR0=0; (* Interrupt flag for PWM match on channel 0 *)
VAR
clearval, reg : SET;
BEGIN
clearval := {};
SYSTEM.GET(LPC.PWM1IR, reg);
IF IRPWMMR0 IN reg THEN
INC(MatchCounter1);
clearval := clearval + {IRPWMMR0}
END;
IF clearval # {} THEN
SYSTEM.PUT(LPC.PWM1IR, clearval) (* clear interrupt flag on match 0 *)
END;
SYSTEM.PUT(LPC.VICAddress, 0) (* Acknowledge Interrupt *)
END IntHandler;
(******************************************************************************
** Function name: PWM.Init
**
** Descriptions: PWM initialization, setup GPI 2.0s to PWM1,
** reset counter, latches is enabled, interrupt
** on PWMMR0, install PWM interrupt to the VIC table.
**
** parameters: None
** Returned value: None
**
******************************************************************************)
PROCEDURE Init*;
CONST
PCPWM1 = 6;
(* P2.0 = PWM1.1 = 1:0 => b0=1 b1=0 *)
MCRPWMMR0I=0; (* Interrupt on PWM MR0 *)
MCRPWMMR0R=1; (* Reset on PWM MR0 *)
VAR
bits : SET;
BEGIN
ResetCounters;
SYSTEM.GET(LPC.PCONP, bits);
IF ~(PCPWM1 IN bits) THEN
SYSTEM.PUT(LPC.PCONP, bits + {PCPWM1}) (* Be sure it is enabled *)
END;
(* Default Clock runs at 1/4 of 72 Mhz = 18 Mhz *)
SYSTEM.GET(LPC.PINSEL4, bits);
SYSTEM.PUT(LPC.PINSEL4, bits - {1} + {0}); (* set GPIO for PWM pin PWM1.1 = function=01 for bits=1:0 *)
SYSTEM.GET(LPC.PINMODE4, bits);
SYSTEM.PUT(LPC.PINMODE4, bits- {0} + {1}); (* No pull-up/down on PWM1.1 = P2.0 output = function=10 for bits 1:0*)
SYSTEM.PUT(LPC.PWM1TCR, {TCRCounterReset}); (* Counter Reset *)
SYSTEM.PUT(LPC.PWM1PR, 0); (* count frequency:Fpclk = 18 Mhz *)
SYSTEM.PUT(LPC.PWM1MCR, {MCRPWMMR0I, MCRPWMMR0R}); (* interrupt on PWMMR0, reset on PWMMR0, reset TC if PWM0 matches *)
SYSTEM.PUT(LPC.PWM1LER, {LER0Enable, LER1Enable});
VIC.InstallHandler(VIC.Pwm1, SYSTEM.ADR(IntHandler), VIC.NormalPriority);
(* You need to .Set a cycle, Then .Start it *)
END Init;
END PWM.
When you do NOT set this in LPC.PWM1MCR, the interrupthandler should not be called.
Code: Select all
MODULE PWMTest;
(* Test on LPC-2378-STK board.
Tiny Program to generate a 38 khz PWM signal on PWM1.1
This wil be the base of a IR - Sender *)
IMPORT Main, PWM, SYSTEM, Out, SYSClock, Timer;
CONST
PWMFreq = 38000; (* PWM frequency *)
PWMDuty = 25; (* 25% high, 75 %low *)
(* Show relevant info on selected Can-channel *)
PROCEDURE CalcFreq() : INTEGER;
VAR
f, val : INTEGER;
BEGIN
f := SYSClock.GetFpclk(SYSClock.PWM1PCLKOffset);
Out.String("PWM1-Clock="); Out.Int(f DIV SYSClock.MHZ, 0); Out.String("MHz"); Out.Ln;
Out.String("Desired PWM freq="); Out.Int(PWMFreq DIV SYSClock.KHZ, 0); Out.String("kHz"); Out.Ln;
val := f DIV PWMFreq;
Out.String("Match Register 0 should use value="); Out.Int(val, 0); Out.Ln;
Out.String("Match Register 1 has duty frequency of ="); Out.Int(PWMDuty,0); Out.String("%"); Out.Ln;
Out.Ln;
RETURN val
END CalcFreq;
PROCEDURE Demo;
VAR
i : INTEGER;
BEGIN
Timer.Init(Timer.MSecs);
PWM.Init;
PWM.Set(CalcFreq(), PWMDuty);
PWM.Start;
Timer.MSecDelay(500);
PWM.Stop;
Out.String("Stopped after "); Out.Int(PWM.MatchCounter1, 0); Out.String(" interrupts. "); Out.Ln;
END Demo;
BEGIN
Demo
END PWMTest.
The code does not suspend the PWM generator but stops it. Suspending a PWM signal might sound handy, but you need to make sure the signal will suspend in a known state, preferrably low. The easy way is just to Stop it. To resume just do a Set, and Start.