Sooty Solutions - Burnaby BC Consulting Company - Advising Business Managers on Security, Information Technology, Business Process Performance, & Best Practices
Sooty HomeContractors are BetterThe Sooty ApproachLong Range PlanningThe Sooty PartnersContact Us
   

68HC11F1 Java Interface

Quick Links
 
  Background
  Microcontrollers
  Vacuum Pumps
  Vacuum Chambers
  Noble Gases
  Power Supplies
  Vacuum Gauges
  Plasma Tests
  Theory
  Simulators
 
  As a taste of the problems using Java in this environment: to dump the MCU registers up the RxTX I need to send the 68HC11 an 81(hex). The 68HC11 always echos the command as a 2s complement so I want to check the echo for 7E(hex). It would be nice if I could define the command as [byte mcuRegDump = 0x81;] and the check the response against [byte mcuRegDumpAck = 0x7E;] but the Java compiler insists I use mcuRegDump=-127 and mcuRegDumpAck=126...sigh.

Talker Properties

The talker is a very small program (TalkJF1 is only 169 bytes) but it is able to read and write memory and all device registers. Using the SWI (Software Interupt Instruction) is is able to stop program execution change the 68HC11 state and resume execution. This gives the talker complete step-by-step control over what happens on the chip.

Some very cleaver people built this into the design of the 68HC11 and that was a major reason for its popularity. It is the basis for JTAG and the SWIM capabilities of the STM chips.

The Motorola "Standard" Talker Uses 5 Commands
$81 - read MCU registers 12 bytes (-$81,stackpointer,CC,B,A,IX,IY,PC)
$C1 - write MCU registers-send 9 bytes: [CC, B, A, IX, IY, PC] to MCU
$01 - read a memory block (1-256 bytes)
$41 - write a memory block (1-256 bytes)
$4A - allow a test program to continue from a breakpoint (SWI)
...all other "commands" just echo the 2s complement of the byte

"Inherent" Commands (high bit set)
$81 [1000 0001] - Transmit MCU registers to PC (12 bytes total)
...returns:
    [7E][STKH-STKl,CC,B,A,IXH-IXL,IYH-IYL,PCH-PCL]

$C1 [0011 1110] - Overwrite MCU registers with bytes read from PC
...returns [3E] acknowledge...now send 9 bytes to the 68HC11:
    [CC,B,A,IXH-IXL,IYH-IYL,PCH-PCL]

These are the registers saved on the stack during an interrupt so the MCU is forced to do a fake interrupt which pushes 9 bytes on stack. The talker then sends to the PC: the 2s complement command, the location of the stack, and the 9 bytes read off the stack. These should be a "frozen" picture of the MCU state.

"Memory" Commands (high bit clear)
[command] [count] [addHigh] [addLow] [data bytes]

where [count]...................0000 to 1111 (0=256 bytes)
         [addHigh][addLow]...16 bit address
         [data bytes]............[count] bytes to write into memory

$01 [0000 0001] [FE] then [count] bytes from memory
$41 [0100 0001] [BE] then send [count] bytes (hangs if not enough sent)

Breakpoint Control of Programs Under Debug Testing
Debugger (IDE) software on the PC inserts a one byte SWI instruction into the memory location just before a "beakpoint". How the IDE deals with added bytes in the machine code is often a trade secret. It may dynamically re-assemble below the SWI, replace/restore bytes displaced by the SWI, or just re-assemble and reload the entire program on every change.

When the SWI is encountered the 68HC11 transmits a $4A (BRKCODE) to the host PC indicating a breakpoint has been reached then loops at SWIIDLE waiting for a reply.

A byte from the PC causes an interrupt...escaping the SWIIDLE loop and branching to SWISRV1.

If the PC sends a $4A (BRKACK) the 68HC11 falls through
...RTI returns to test program.

If the PC does not send a $4A (or a valid [command]) the 68HC11:
...transmits [addHigh][addLow] of the breakpoint address
...transmits a copy of the MCU registers (9 bytes)
...the [PCL] byte is left in the SCI buffer for the test program to read

If the PC sends a valid [command] (not a $4A) the 68HC11 will process
{$81, $C1, $01, $41} ...then RTI back to the test program

Java and Microcontrollers

Java is a terrible language to use with microcontrollers...it (and its Microsoft C# variant) is however an extremely popular language for web applications. That means most who read this will be Java programmers.

Realms have their favorite languages. Physics (astrophysics, plasma physics, meteorology) and enginering (civil, structural) are [large data set] [compute intensive] and rely on weakly typed languages like C and FORTRAN (for..what?). Most of the worlds financial systems still run COBOL (co..what?) and high frequency trading code is all C++. Games, operating systems and AI are also C++ realms. If you work in those fields and only know Java you'll get to write the room booking app or the bulk emailer.

For microcontrollers the code that runs inside the chips is almost always created by an assembler, C or C++. As a result the tools (written by the same people) that support the environment are written in C or C++.

C is "weakly typed" which means a block of data can be a string or an array of bytes or an array of floating point numbers or an IP address at different places in the code. This makes communications easy because a message may have many data types packed into a single compact stream of bytes. It can also make for very challanging debuging when a URL location is accidently used as floating point GPS location.

Java can be used with micronctrollers but the code looks weird. There are no good ways to cast one data type into another so basic strategy is to pass raw data through a print formatter (that doesn't care about type) then parse it out as a string. When that doesn't work you have to figure out how Java actually stores its objects and trick it into having the right bytes in the right place. This makes the code hard to read.

For example to get the MCU registers you need to send 81(hex) to the 68HC11. If talker is in a "sane" state it will echo the 2s complement of the command 7E(hex) then the binary content of 6 registers; some that are single byte (like the condition codes CC) and some are two byte (like the program counter PCH-PCL). The 81(hex) is an "Inherent" command because the high bit is set. The high bit is critical to the flow of the talker program during execution.

If Java let you [byte mcuRegDump = 0x81;] it would be clear what is happening. Java has no unsigned data type so setting the high bit in a byte is not allowed. What you must do is [byte mcuRegDump = -127;] because the - sign sets the high bit and 128-127=1 set the low bit. That gives you [1000 0001] which is 81(hex).

Lying to the compiler to get it to do what you want is poor programming practice. The example code that follows is full of such poor parctices.

Talking to the Talker

The standard Java IO libraries are meant to talk to file systems and object orientated display drivers. They have clumsy with low level device interfaces (although I understand this is getting better). Long ago the standard libraries were abandoned and for a specialized serial I/O libary. The best replacement is RXTXComm.

In the zip archive you will find both 32 bit and 64 Windows versions. Create a C:\RXTXcomm and RXTXcomm.jar into it. Copy the rxtxSerial.dll (and the rxtxParallel.dll) to the \bin path in you Java development installation. My examples use 6.22 on 64 bit Windows 7 so the dll should be in C:\Program Files\Java\jdk1.6.0_22\bin\rxtxSerial.dll.

If you don't have a Java development environment can get the "Java SE Development Kit 6u22" from 1.6_22 JDK. The current version of the Java Standard Edition (SE) Development Kit (DK) is 1.8_40 (I actually develop in 6.22, 7.03 and 8.11) and my examples should run fine under Java 8 but they are certain to run under Java 6. You can find all versions of the SDK in the Oracle arachive.

If you don't use 1.6_22 you'll need to change the .cmd to reflect which JDK you are using.

The Java Samples ZIP contains four programs:
TwoWaySerialComm.java...example from the RxTx Project pages
TalkerJF1.java.................reads all the assets from the 68HC11
Voltmeter.java.................reads A/d samples one at a time from the PC
Voltprog.java...................load a volts.s19 into the 68HC11 for fast A/D

For running TalkerJF1.java and asking for the device registers displays:
(see the TalkerJF1x64.log)

  +-------------------------------------------+
  |Commands:                                  |
  |  ^C kill this run                         |
  |   F to send eight FFs (attempt to resync) |
  |                                           |
  |   R dump the MCU registers                |
  |   G dump all I/O registers {A,B,C,D,E,G}  |
  |                                           |
  |   E dump the  512 byte onchip EEPROM      |
  |   M dump the 1024 byte onchip RAM         |
  |                                           |
  |   H display this help message             |
  +-------------------------------------------+
  r
  Sending to MCU < 81 >

  MCU Registers:
  03 F7 40 2C 40 10 00 FF FF FE 12
  Stack CC  B  A [IX ] [IY ] [PC ]
  g
  Sending to MCU < G >

  GIO Ports accessed via 96 bytes starting at 1000(hex):
  ------------------------------------------------------

        +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
  1000  05 00 4B 00 00 00 00 00 23 00 40 00 00 00 B1 CC
  1010  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
  1020  00 00 00 F8 00 C0 00 00 04 00 00 30 00 2C 10 00
  1030  80 00 00 00 00 1F 4F 4F 20 10 4F 00 05 01 00 FF
  1040  4F 4F 4F 4F 4F 4F 4F 4F 4F 4F 4F 4F 4F 4F 4F 4F
  1050  4F 4F 4F 4F 4F 4F 4F 4F 4F 4F 4F 4F 00 04 00 07

  Selected Ports and Direction Control:
  -------------------------------------
  Port A (1000):  05(hex)  00000101
  ..DDRA (1001) direction (in=0, out=1) 00000000

  Port B (1004): 00(hex)  00000000 output only

  Port C (1006): 00(hex)  00000000
  ..DDRC (1007) direction (in=0, out=1) 00000000

  Port D (1008): 23(hex)  00100011
  ..DDRD (1009) direction (in=0, out=1) 00000000

  Port F (1005): 00(hex)  00000000 output only

  Port G (1002): 4B(hex)  01001011
  ..DDRG (1003) direction (in=0, out=1) 00000000

  Port E (100A) may be used for binary input or as analog input for A/D
  ---------------------------------------------------------------------
  Port E (as binary): 40(hex)   01000000  [Do not read E during A/D]

  If Port E was used for A/D:
  ---------------------------
  A write to ADCTL starts A/D conversion

  ADCTL (1030): 80(hex)  10000000
	CCF        (bit 7) = 1        (1=Conversion complete)
	not used   (bit 6)    .
	SCAN       (bit 5) =   0      (0=do 4 samples & stop, 1=continuous)
	MULT       (bit 4) =    0     (0=use single channel, 1=use 4 channels)
	CD         (bit 3) =     0    (4 channels...0=use {0123}, 1=use {4567})
	CC/CA (bits 2,1,0) =      000 (1 channel...read from this port E pin)

  A/D data registers
  ------------------
  ADR0 (1031) data for A/D channels 0 & 4 = FF(hex)  11111111
  ADR1 (1032) data for A/D channels 1 & 5 = 00(hex)  00000000
  ADR2 (1033) data for A/D channels 2 & 6 = 00(hex)  00000000
  ADR3 (1034) data for A/D channels 3 & 7 = 00(hex)  00000000

Voltmeter.java writes a [0000 0000] [do 4 samples and stop, use channels 0..3) to the ADCTL (1030hex) register to trigger a A/D conversion on channels 1..4 written into registers ADR0..ADR3. It then does a memory read [01]hex on [1] byte from address [10][31] then converts the 8 bit data byte and reports it as the actual 0.0V to 5.0V range.

With a 1 volt AC applied to pin 59 (AD0) the program provides a continous report of voltages (see the Voltmeter.log):