This examples shows interfacing with Olimex UEXT plugin module, in this case combined with LPC2378-STK board. The clock using I2C interface.
After some study of MOD-RTC schematic I have created the following MODULE:
Code: Select all
MODULE UEXTMODRTC;
(* FOR ARM LPC2378-STK Board interfacing with UEXT connector, the following UEXT pins are used:
NAME = GPIO = DIR NAME ON MOD-RTC PIN-PU/PD
1 +3V3 +3V3
2 GND GND
3 TXD2 = P0.10 = IN CLKOUT PCF8563 clock output. (* 4.7k PU on LPC2378 *)
4 RXD2 = P0.11 = IN #INT PCF8563 interrupt output, active LOW. (* 4.7k PU on LPC2378 *)
5 SCL0 = P0.28 = I/O SCL I2C; 4.7k PU on LPC2378-STK because Open Drain Output
6 SDA0 = P0.27 = I/O SDA I2C; 4.7k PU on LPC2378-STK because Open Drain Output
7 MISO1 = P0.8 = not used
8 MOSI1 = P0.9 = not used
9 SCK1 = P0.7 = not used
10 SSEL1 = P0.6 = not used
*)
IMPORT SYSTEM, LPC := LPC2378, I2C;
CONST
(* All pins are of Port 0 *)
CLKPin* = 10; (* UEXT Pin-3, is P0.10, Configured as Input *)
INTPin* = 11; (* UEXT Pin-4, is P0.11, Configured as Input *)
PROCEDURE InitRTC*;
VAR
bits : SET;
BEGIN
(* Configure for GPIO /FIO *)
SYSTEM.GET(LPC.SCS, bits);
IF ~(0 IN bits) THEN
SYSTEM.PUT(LPC.SCS, bits + {0}) (* enables GPIO on ports 0 and 1 *)
END;
(* setting pins to function as GPIO
P0.10 = bits 21:20 = 0:0, P0.11 = bits 23:22 = 0:0
*)
SYSTEM.GET(LPC.PINSEL0, bits);
SYSTEM.PUT(LPC.PINSEL0, bits - {20..23}); (* configure P0.10, p0.11 for GPIO *)
(* setting pin pu/pd resistors none needed, because wired on board(s)
P0.10 = bits 21:20 = 1:0, P0.11 = bits 23:22 = 1:0 *)
SYSTEM.GET(LPC.PINMODE0, bits);
SYSTEM.PUT(LPC.PINMODE0, bits - {20,22} + {21,23});
(* setting direction of the pins P0.10, P0.11 to input *)
SYSTEM.GET(LPC.FIO0DIR, bits);
SYSTEM.PUT(LPC.FIO0DIR, bits - {CLKPin, INTPin});
END InitRTC;
PROCEDURE InitI2C*(bus: INTEGER);
(* Ref: LPC2xxx User Manual *)
CONST
freq = 100000;
VAR
select: SET;
BEGIN
(* Configure for GPIO /FIO *)
SYSTEM.GET(LPC.SCS, select);
IF ~(0 IN select) THEN
SYSTEM.PUT(LPC.SCS, select + {0}) (* enables GPIO on ports 0 and 1 *)
END;
IF bus = 0 THEN
(* LPC2378 I2C0 Deviation: uses different pins *)
(* Connect I2C0 signals
P0.27 to SDA0 = 23:22 = 0:1
P0.28 to SCL0 = 25:24 = 0:1 *)
SYSTEM.GET(LPC.PINSEL1, select);
SYSTEM.PUT(LPC.PINSEL1, select - {23, 25} + {22, 24})
ELSE
(* LPC2103 I2C1 *)
(* Connect I2C1 signals (SCL1 & SDA1) to P0.17 and P0.18 *)
SYSTEM.GET(LPC.PINSEL1, select);
SYSTEM.PUT(LPC.PINSEL1, select - {3, 5} + {2, 4})
END;
I2C.Init(bus, freq)
END InitI2C;
END UEXTMODRTC.
Code: Select all
MODULE MODRTC;
(* =========================================================================
Example ARM Oberon I2C Real Time Clock Interface Program
Description:
Set and Reads the MOD-RTC Real-time Clock/calender and demonstrates
use of I2C / UEXT interface on LPC2378-STK
Target:
LPCxx systems with a MOD-RTC module connected to a Olimex UEXT connector
connected to the I2C0 or I2C1 bus
Tested with:
Olimex LPC-2378-STK
(I2CBUS = 0)
Embedded Artists LPC2103 Education Board
Embedded Artists LPC2148 Education Board v3
(I2CBUS = 1)
Coridium Corp LPC2103 ARMmite
Coridium Corp LPC2103 ARMmite PRO
Refs:
NXP LPC2103 User Manual UM10161
NXP PCF8563 Real-time clock/calendar Datasheet
Oberon for LPC2000 Microcontrollers
========================================================================= *)
IMPORT LPC, I2C, SYSTEM, Main, Out, Timer, UEXT := UEXTMODRTC;
CONST
(* Set I2CBUS to 1 for ARMmite and ARMmite PRO *)
(* Set I2CBUS to 0 for all other boards *)
I2CBUS = 0; (* 0 is OK for LPC2378, but pins used on LPC2378-STK differ, See Init *)
(* This results in use of address A2 (write) and A3 (read) *)
RTCAddr = 051H;
(* Registers of RTC *)
Status1 = 0;
Status2 = 1;
Seconds = 2; (* Msb contains Voltage Low Flag *)
Minutes = 3;
Hours = 4;
Days = 5;
Weekdays = 6;
Months = 7; (* Msb contains Century Flag *)
Years = 8;
MinuteAlarm = 9;
HourAlarm=10;
DayAlarm=11;
WeekdayAlarm=12;
ClkOutControl=13;
TimerControl=14;
Timero=15;
(* Converts a number to the BCD format tttt|uuuu (tens and units)*)
PROCEDURE CharToBCD(a : SYSTEM.BYTE) : SYSTEM.BYTE;
BEGIN
RETURN CHR(ORD(a) MOD 10 + (ORD(a) DIV 10 * 16))
END CharToBCD;
(* Converts a BCD coded register back to a binary number *)
PROCEDURE BCDToChar(a : SYSTEM.BYTE; mask : SET) : SYSTEM.BYTE;
VAR
sub : INTEGER;
BEGIN
sub := 10 * ORD(SYSTEM.VAL(SET, ORD(a) DIV 16) * mask);
RETURN CHR(ORD(a) MOD 16 + sub)
END BCDToChar;
PROCEDURE Progress(msg: ARRAY OF CHAR; status: INTEGER);
BEGIN
Out.String(msg);
IF status = I2C.OK THEN
Out.String(" OK")
ELSE
Out.String(" Error ");
Out.Int(status, 0)
END;
Out.Ln
END Progress;
PROCEDURE Dow(d : CHAR; VAR daystr : ARRAY OF CHAR);
BEGIN
IF ORD(d) > 6 THEN
daystr := ""
ELSE
CASE d OF
0X : daystr := "Sunday"
|1X : daystr := "Monday"
|2X : daystr := "Tuesday"
|3X : daystr := "Wednesday"
|4X : daystr := "Thursday"
|5X : daystr := "Friday"
|6X : daystr := "Saturday"
END
END
END Dow;
PROCEDURE OutTimeDate(sec, min, hr, day, wd, month, year : SYSTEM.BYTE);
VAR
days : ARRAY 12 OF CHAR;
BEGIN
Out.String("Time: ");
Out.Int(ORD(hr), 2); Out.Char(":"); Out.Int(ORD(min), 2); Out.Char(":"); Out.Int(ORD(sec), 2); Out.Ln;
Out.String("Date: ");
Out.Int(ORD(day), 2); Out.Char("-"); Out.Int(ORD(month), 2); Out.Char("-"); Out.Int(ORD(year), 2); Out.Ln;
Out.String("Day of the week: ");
Dow(SYSTEM.VAL(CHAR, wd), days);
Out.String(days); Out.Ln
END OutTimeDate;
(* Sets the date and time to the specified values
if the value is outside the allowed range
it will be set to zero
returns TRUE if successful, 0 if there was an ERROR while writing
ranges: sec(0-59), min (0-59), hr(0-23), day(0-31), weekday(0-6,Sun=0)
month(1-12), year(0-99)
*)
PROCEDURE SetTimeDate(sec, min, hr, day, wd, month, year : SYSTEM.BYTE) : BOOLEAN;
VAR
result : BOOLEAN;
status : INTEGER;
ap : ARRAY 1 OF SYSTEM.BYTE; (* array of parameters to pass, don't depend on LEN! *)
ca : ARRAY 7 OF SYSTEM.BYTE; (* clock values to set *)
BEGIN
IF ORD(sec) > 59 THEN sec := 0X END;
IF ORD(min) > 59 THEN min := 0X END;
IF ORD(hr) > 23 THEN hr := 0X END;
IF ORD(wd) > 6 THEN wd := 0X END;
IF (ORD(month) = 0) OR (ORD(month) > 12) THEN month := 1X END;
IF ORD(year) > 99 THEN year := 0X END;
ca[0] := CharToBCD(sec);
ca[1] := CharToBCD(min);
ca[2] := CharToBCD(hr);
ca[3] := CharToBCD(day);
ca[4] := CharToBCD(wd);
ca[5] := CharToBCD(month);
ca[6] := CharToBCD(year);
ap[0] := 02X; (* Set the register to start read wiaddress pointer to 2 *)
Timer.MSecDelay(20);
(* DON'T use I2C.Write *)
status := I2C.WriteBytes(RTCAddr, ap, 1, ca, 0, 7);
Progress("MODRTC.SetTimeDate=", status);
RETURN status = I2C.OK
END SetTimeDate;
(* Gets the current time (in decimal format)
returns TRUE if successful, FALSE if there was an ERROR while reading
*)
PROCEDURE GetTimeDate(VAR sec, min, hr, day, wd, month, year : SYSTEM.BYTE) : BOOLEAN;
VAR
status : INTEGER;
ap : ARRAY 1 OF CHAR; (* Array of parameters to pass *)
ca : ARRAY 7 OF CHAR; (* clock array that receives data *)
BEGIN
Timer.MSecDelay(20);
ap[0] := 02X; (* Address to start reading = RTC register#2 *)
(* DON'T use I2C.Read !! *)
status := I2C.ReadBytes(RTCAddr, ap, 1, ca, 0, 7); (* Reads 7 bytes starting from RTC register# 2 *)
Progress("MIDRTC.GetTimeDate=", status);
IF status = I2C.OK THEN
sec := BCDToChar(ca[0], {0,1,2});
min := BCDToChar(ca[1], {0,1,2});
hr := BCDToChar(ca[2], {0,1});
day := BCDToChar(ca[3], {0,1});
wd := CHR(ORD(ca[4]) MOD 8);
month := BCDToChar(ca[5], {0});
year := BCDToChar(ca[6], {0..3})
END;
RETURN status = I2C.OK
END GetTimeDate;
PROCEDURE dummy(aoc : ARRAY OF CHAR);
VAR
i : INTEGER;
BEGIN
i := LEN(aoc);
Out.String("LEN-Length of array = ");
Out.Int(i, 2);
Out.String(", Is this what you expected?");
Out.Ln;
END dummy;
PROCEDURE Run;
VAR
test1 : ARRAY 1 OF CHAR; (* allocates 4 bytes *)
sec, min, hr, day, wd, month, year : SYSTEM.BYTE;
status : INTEGER;
BEGIN
dummy(test1); (* demonstrates compiler rounding on length of a 1 byte array
which makes use of LEN USELESS on CHAR/BYTE array *)
status := I2C.OK;
hr := CHR(11); min := CHR(15); sec := CHR(45); (* 11:15:45 = hh:mm:ss *)
day := CHR(29); wd := 6X; month := CHR(9); year := CHR(12); (* 2012, september 29, saturday = day no.6 *)
IF SetTimeDate(sec, min, hr, day, wd, month, year) THEN
REPEAT
IF GetTimeDate(sec, min, hr, day, wd, month, year) THEN
OutTimeDate(sec, min, hr, day, wd, month, year)
END;
Timer.MSecDelay(30000) (* Wait 30 seconds *)
UNTIL FALSE
ELSE
Out.String("Could not set clock")
END
END Run;
BEGIN
UEXT.InitRTC;
UEXT.InitI2C(I2CBUS);
Run
END MODRTC.
- Conversion To/From Values to BCD and back
- Interfacing with UEXT module
- Interfacing with I2C
- A reminder that rounding array lengths can cause problems in Interfacing
- Adding functionality to a board without soldering
Have Fun!0