DMP1 System Time Hacking

From Omnifi Wiki

Jump to: navigation, search
Quick Links
Linux-Inside.jpg
Related topics
  • Find Something
    • To Put Here

edit

A quick documentation of the DMP1's real-time clock and wakeup alarm. Major contributors are Dan Zenchelsky, Andy Poling, Lincomatic. Thanks!

Contents

Paradox

While the DMP1's CPU (EP7312) is an ARM 720T compatible processor made by Cirrus Logic and incorporates real time clock is a 32-bit counter (Real Time Clock Data Register ref 1:p 3-3)(1) and a wake up timer (Real Time Clock Match Register ref 1:p 3-4)(1), neither of these handy registers are used for any date-time and alarm settings on board the DMP1.

Real Time Clock (RTC):

On board the DMP1 motherboard resides a PIC (PIC16LF low voltage programmable controller)(4) that is programmed with a 32-bit real-time timer that starts at zero upon application of power to the 12v Constant line. It resolution is 1Hz, meaning that it will count up by one for every second elapsed. Thus the contents of this timer contains the number of seconds elapsed since power was initially applied to the unit. As long as power is applied to the 12v constant line, the PIC will continue to increment this register at 1 second intervals.

Note: the resolution of this timer is evidently actually 2HZ, thus it starts at zero, and increments by two every other second. Flamozzle 08:32, 4 February 2009 (PST)

The contents of this timer is available by reading from the /dev/sermodr device. This device constantly outputs various signals, from real-time clock ticks to keypad button presses and battery voltage levels(2). The /dev/sermod* talks directly to the PIC through an RS-485 interface.

The real-time clock ticks are automatically reported every two seconds on the /dev/sermodr device and are prefaced by a 3 character header 0A8(2), followed by an 8 digit hex representation (32-bit) of the contents.

Additionally, one of the OS environment variables is utilized for setting the OS clock. The CP_ENV_POWER_UP_TIME variable contains a value expressed in decimal and represents some absolute time in the past when the DMP1 had power reapplied / applied to it for the first time. That is, the time in which the PIC clock read 0 (zero) seconds. This value is expressed in elapsed seconds since the Jan 1, 1970 00:00 epoch, and is compatible with Unix / Linux epoch times as well as the C/C++ time_t type (from time.h).

The real-time clock tick from /dev/sermodr is added to the CP_ENV_POWER_UP_TIME value and represents the number of seconds elapsed since the epoch, and this value is used to set the DMP1's kernel clock (system clock) during the boot up phase.

When the DMP1 is synchronized with SimpleCenter using the manually-initiated wireless sync, the SimpleCenter PC's system time is transmitted to the DMP1 which in turn sets its system clock by it.

Additionally, in order that the time correction (if any) will hold after the DMP1 is rebooted, a new CP_ENV_POWER_UP_TIME value is recalculated by comparing the new system time to the real-time clock.

CUR_TIME = current time in Unix Time format (seconds elapsed since epoch)
RTC_TIME = PIC clock time reported by Real Time Clock (via /dev/sermodr)
CP_ENV_POWER_UP_TIME = CUR_TIME - RTC_TIME

This value is exported to the DMP1's shell environment using:

export CP_ENV_POWER_UP_TIME='<new time>'

where <new time> is the value calculated above and represented in DECIMAL. Additionally, a /sbin/saveenv command is invoked which does the following at a high level:

  1. remounts /dev/mtdblock/5 as /.persistent as Read/Write
  2. writes the contents of the environment variables to /.persistent/profiles.current in the form of various export statements
  3. writes the contents to flash memory

The next time the DMP1 is powered on, the contents of the flash memory (/dev/mtdblock/5) is mounted, and the environment variables are restored from /.persistent/profiles.current, then the system datetime is set using the simple alogorithm described above.

Wake Up Alarm:

The PIC16LF RTC will continue to increment the RTC counter register even during periods of low-power operation (that is, the car ignition switched off and all of the functions of the DMP1 and EP7312 processor completely powered down except for the PIC)

Alongside the PIC RTC is a Wake Up Time Register which can be programmed by an application to cause the DMP1 to power on at a specific time. This is a 32-bit read/write register which reads and sets the binary match time to the PIC's Real-Time Clock timer. If this value matches the value in the Real-Time Clock Data Register, it will issue an interrupt which will cause the DMP1 to power up and go through the boot cycle.

This is how the Stock DMP1 software performs the nightly syncs. The value that is written to this register must match the value that will eventually be attained by the constant ticking of the PIC's Real-Time Clock register. That is, in order for this to work, the value put into this Wake Up register must be sometime in the "future." If this time is in the past a wakeup will no longer occur. Additionally, an application that relies on this wake up feature must periodically inspect and set the next wakeup period if the current wake up time has passed.

The wakeup tick value is calculated as:

DESIRED_WAKEUP_TIME = time to wakeup (expressed in seconds since epoch) in the future
WAKEUP_TICK = ( DESIRED_WAKEUP_TIME - CP_ENV_POWER_UP_TIME - PIC_RTCTick )

alternately

CURRENT_TIME = current time (expressed in seconds since epoch)
WAKEUP_TICK = ( DESIRED_WAKEUP_TIME - CURRENT_TIME )

This value can then be written to the /dev/sermodq device (which is a write device) that will update the PIC's Wake Up register. Consider the following program:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
  int fileDescriptor;
  char readBack[32];
  printf("Setting wakeup timer and shutting down\n");
  if ((fileDescriptor= open("/dev/sermodq", O_RDWR)) >=0) {
    write(fileDescriptor, "3C2", 3);
    write(fileDescriptor, "2dE00069190", 11);
    read(fileDescriptor, readBack, 32);
    write(fileDescriptor, "2bD00", 5);
  } else {
    printf("Failed to open /dev/sermodq.\n");
    return 1;
  }
  return 0;
}

This program, when run on the DMP1(3) will write out some value of clock ticks to the Wake Up Timer and exit. The WAKEUP_TICK value, highlighed in blue above, is a Hexadecimal value.

Open /dev/sermodq for read/write
Get /dev/sermodq's attention by writing a '3C2' character stream
Send /dev/sermodq a header '2dE' followed by 8 Hexadecimal-encoded character stream of WAKEUP_TICK
Pause for a readback
Send /dev/sermodq a '2bD' (poweroff countdown) followed by a hexadecimal-encoded number of seconds

The DMP1 unit and HD will shutdown immediately and while the faceplate remains on. You can safely shutdown the car at this point. You will, of course, calculate your own value for WAKEUP_TICK and substitute it for the value in blue above. When the specified wake up time is achieved and the DMP1 is powered down, it will begin its bootup cycle and boot into the omnifi application.

See Also

External References

  1. Cirrus Logic EP73xx User's Guide
  2. Andy Poling's Reverse_Engineering_Notes.txt from his openfi sourceforge project
  3. Setting_Up_An_ARM_Cross_Compiler
  4. Rockford Fosgate Car Omnifi Technical Analysis

Additional References:

  1. PIC16 Series Datasheet


--Lumkichi 08:13, 25 Oct 2005 (CDT)

Personal tools