Last updated 6.2.06.
- Introduction
- The H8/3292 Microcontroller
- The RCX: CPU, Memory and Input/Output Devices
- The RCX CPU
- The RCX Memory
- The RCX Input/Output Devices
- Access to RCX Device Registers
- RCX Interrupts and Interrupt Handlers
- Buttons
- RCX Input Ports and Sensors
- Infrared Transmitter/Receiver
- Liquid Crystal Display (LCD)
- Speaker
- RCX Output Ports and Actuators
- The RCX Executive
- Communication with the RCX Executive
- The Request/Reply Protocol
- The Byte Protocol
- The Bit Protocol
- The RS232 Connected Infrared Transmitter/Receiver
- A Program to Communicate with the RCX Executive
- The RCX Executive as a Run-time Environment
- LCD Routines
- Compilation of Programs for the RCX
- How to Install Cross-Assembler and Cross-Compiler
- Translation of Assembly Language Programs
- Compilation of C-Programs
- Download of Programs to the RCX
- References
Embedded into the RCX is a microcontroller, a Hitachi H8/3292, with a CPU, called the H8/300 CPU Core. This CPU runs the control program. Through the H8/3292 based device controllers the control program access RCX input/output devices like buttons, a speaker, and a special purpose Liquid Crystal Display (LCD). Furthermore, sensors like a touch sensor or a temperature sensor can be connected to the RCX input ports providing sensor input to the control program and the control program can activate actuators like motors connected to the RCX output ports. Stimuli from the environment - a car bumping into an obstacle - can be registered by a sensor, e.g. a touch sensor, and transformed into input values for the control program. The resulting response - turning the car - can be accomplished by the control program through values output to actuators, e.g. a motor.
The RCX is equipped with the following input/output devices:
| Input devices |
|---|
| Four buttons labelled Run, OnOff, View, Prgm |
| Three input ports labelled 1,2,3 |
| Battery voltage level |
| Timers |
| Infrared receiver |
| Output devices |
|---|
| Liquid Crystal Display |
| Speaker |
| Three output ports labelled A,B,C |
| Infrared transmitter |
The RCX interacts with the environment through these input/output devices and sensors/actuators connected to the RCX input/output ports. The following sensors/actuators are available:
| Sensors | Examples of stimuli |
|---|---|
| Touch sensor | Obstacle encountered, go signal on a touch button |
| Light sensor | Color reflection, ambient light |
| Rotation sensor | Angle turned by wheels, movements of shaft |
| Temperature sensor | Body temperature, outdoor temperature |
| Actuators | Examples of response |
|---|---|
| Motor | Movements of car, elevator going up |
| Lamp | Flashing light, red alarm light |
| Sound element | Buzz sounds |
The development of control programs takes place on a host computer (a PC or a UNIX machine). The control program is brought to the RCX through a download on a serial communication link provided by the infrared transmitter/receiver. The control program can be developed in different programming environments offered by LEGO: ROBOLAB, a graphical programming environment hosted on a PC; Software Developers Kit (see the entry on LEGO MindStorms), an environment hosted on a PC that uses Visual Basic as a host language for download of rather low level machine-code like control programs.
This manual describes a simple programming environment hosted on a UNIX machine. Programs can be written in the high level language C and in assembly language for the H8/300 CPU. Programs are cross-compiled/cross-assembled to native H8/300 code and downloaded to the RCX by means of a simple protocol provided by the on-chip ROM resident RCX executive running on the H8/3292 after power up and reset. After download the program is started and the RCX executive can serve as a run-time environment for the program providing services like I/O routines for access to the RCX input/output devices, e.g. the LCD. Also, this manual gives details that makes it possible to program direct access to the RCX input/output devices through the memory mapped device registers interfacing the CPU to the device controllers.
This manual and the UNIX programming environment can be used as tools to develop simple control programs for the native RCX but it can also be used as tools for developing programming environments for the RCX like a Real-Time Operating System.
The H8/300 CPU is based on a general register architecture. The instruction set include register-register arithmetic and logic operations. The addressing modes include most of the common addressing modes like register direct, register indirect, program counter relative, and memory indirect. The address space is 16-bit (64 Kbytes) for program and data combined.
The on-chip memory consists of 16 Kbytes mask programmable ROM and 512 bytes RAM. Furthermore, a 128 bytes on-chip register field is used as memory mapped registers to interface to the on-chip input/output circuitry. The memory map defines how the on-chip memory and possible external off-chip memory maps into the 16-bit address space. The memory map is partly defined by the input level on two pins on the chip (called MD1 and MD0; these can be accessed as bit 1 and bit 0 of the Mode Control Register at address 0xffc5 in the register field). These two bit select an operating mode of the microcontroller (mode 1, 2 or 3). In all modes the on-chip RAM and the on-chip register field maps to the same addresses. In mode 1 and 2, called expanded modes, it is possible to access external off-chip memory and off-chip device registers through the address/data pins of the microcontroller chip. In mode 3, called single-chip mode, only on-chip ROM and RAM, and the on-chip register field is available. When external memory is used it is mapped into the address space by means of the external logic for address decoding.
On-chip input/output includes three types of timers (a 16-bit free running timer, 8-bit timers, and a watch dog timer), a serial communication interface, an Analog/Digital converter, and input/output ports. The timers can be used without off-chip circuitry. The serial communication interface can act as a device controller for an external serial transmitter/receiver. Similarly, the 10-bit A/D converter can be turned into a device controller for up to eight analog channels. The external analog input on an input line connected to one of the eight pins of the A/D converter can be sampled by an on-chip sample-and-hold circuit and converted to a 10-bit value available in a device register. An on-chip analog multiplexer can operate in both a single shot and scan mode. Scan mode allows continuous conversion on more channels delivering digital results in different device registers. The pins of the input/output ports can be connected to off-chip input or output lines. When the processor reads from a device register corresponding to an 8-bit input port, the byte value returned reflects the 1's and 0's on the input lines. With almost no external circuitry an external button can be directly connected to an input line and the state of the button can be input from the input port. When the processor writes into a device register corresponding to an 8-bit output port, the byte value of 1's and 0's placed in the register is output to the pins of the output port and the output lines connected to the pins can be used directly to drive external circuitry like a Light Emitting Diode (LED)
An on-chip interrupt controller provides an interrupt mechanism for both internal and external interrupts. Internal interrupts are generated caused by events in the on-chip input/output components. Each separate event (e.g. end of A/D conversion and timer overflow) interrupts though a separate interrupt vector. External interrupts are generated caused by external events signalled through pins on the microcontroller chip (e.g. a pin for Non Maskable Interrupt (NMI)). All interrupts can be globally or individually disabled or enabled (except NMI).
Physically, the electronics of the computer inside the RCX consists of a printed circuit board and a 9V battery based power supply. On the circuit board chips and other electronic components are mounted and connected, e.g. the H8/3292 single-chip microcontroller, a 32Kbytes RAM chip, chips for motor control, LCD screen and LCD controller chips, a speaker, connections to the RCX input/output ports on the plastic cover, and contacts for the four rubber buttons. Pictures of a disassembled RCX with a detailed list of components can be obtained from RCX Internals.
The logically structure of the RCX controller is that of a simple low-end personal computer with a single bus used to connect the processor, memory and input/output devices. Input/output is memory mapped and each device consists of two parts: one containing the electronics interfacing the device to the bus, and one containing the mechanical and electronical components of the device itself. Examples of mechanical and electrical components of devices in the RCX includes buttons, LCD screen, and speaker but also the mechanical and electrical constructions build out of LEGO bricks including the sensors and and actuators interfacing these application dependent devices to the RCX. This shows that the level of abstraction determines what is to be considered as the interfacing part and what is to be considered as the device itself. The interfacing part is normally referred to as the device controller.
It is the logically structure that is useful to think of when programming the RCX controller. The components of the logically structure will now be described from a programmers point of view.
| Address mode | Assembly language |
|---|---|
| Register direct | rn |
| Register indirect | @rn |
| Register indirect with 16-bit displacement | @(d:16,rn) |
| Register indirect with post-increment | @rn+ |
| Register indirect with pre-increment | @-rn |
| Absolute address (8 or 16 bits) | @aa:8, @aa:16 |
| Immediate (8-, or 16-bit data) | #aa:8, #aa:16 |
| pc-relative (8-bit displacement) | @(d:pc) |
| Memory indirect | @@aa:8 |
The memory map is thus determined by the choice of mode 2 and the external address decoding. The resulting memory layout is as follows:
| Addresse range | Memory type | Contents |
|---|---|---|
| 0x000 - 0x3fff | on-chip mask programmable ROM | H8/3292 interrupt vectors, RCX executive |
| 0x8000 - 0xefff | off chip RAM | program/data |
| 0xf000 | off-chip register | device register for RCX output ports |
| 0xfd80 - 0xff7f | on-chip RAM | RCX interrupt vectors/program/data |
| 0xff88 - 0xffff | on-chip register field | H8/3292 device registers |
A program running on the RCX CPU communicate and synchronize with the RCX devices in the usual way through device registers and interrupts. Hence, the communication and synchronization interface for each RCX device controller is the RCX device registers and RCX interrupts that is provided by the RCX device controller.
Most of the RCX device controllers are based on the H8/3292 input/output components. The memory mapped device registers of the H8/3292 input/output component is also used as the RCX device registers and the interrupts provided by the H8/3292 input/output component are also used as RCX device interrupts. The only exception is the RCX output ports. These are based on external electronic components; hence, the RCX output port controller do not use the H8/3292 input/output components. The device registers of the RCX output controller is accessed through the address/data pins of the H8/3292. This means that they are memory mapped into the address space not used by on-chip memories. Therefore, the RCX device registers of the RCX output ports are not part of the on-chip register field address range.
The RCX device controllers are based on the H8/3292 componets as follows:
| RCX device controlled | Device registers | Interrupts |
|---|---|---|
| buttons | device registers of I/O port 4 and 7. Two input lines of port 4 and two of port 7 are used. IRQ0, IRQ1 device registers | Run is connected to IRQ0, OnOff to IRQ1 |
| input ports | device registers of A/D converter and device registers of I/O port 6. Three output lines of port 6 are used | A/D interrupt |
| battery voltage level | device registers of A/D converter | A/D interrupt |
| timers | device registers of timers | timer interrupts |
| infrared transmitter/receiver | device registers of SCI, I/O port 4, and timer 1. One output line of port 4 is used | SCI interrupts, timer 1 interrupts |
| LCD | device registers of I/O port 6. Two lines of port 6 are used | no interrupts |
| speaker | device registers of I/O port 6 and timer 0. One output line of port 6 is used | timer 0 interrupt |
| output ports | device register in external address space | no interrupts |
The typecast in the first define turns the address constant 0xffe8 into a pointer to a byte. The *( ...) takes the content of the byte pointed to by the address. The volatile qualifier is needed to prevent an optimizing compiler to read the content of the byte or word only once e.g. outside a loop that waits for the value of the device register to change. These types and definitions can be used to e.g. start a conversion of A/D channel 0, wait for end of conversion and read the resulting 10 bits from the A/D data register A:typedef unsigned char byte; typedef unsigned short int word; /* A/D converter */ /* A/D Control/Status Register */ #define ADCSR *((volatile byte *) 0xffe8) #define ADF ( 1 << 7 ) /* A/D Flag , bit 7 */ #define ADST ( 1 << 5 ) /* A/D Start, bit 5 */ /* A/D Data Register A */ #define ADDRA *((volatile word *) 0xffe0)
Bitwise operations in C are described in Kernighan & Ritchie, p. 48, 49 and p. 149, 150.ADCSR = 0; ADCSR |= ADST; /* Start conversion */ while ( ! ( ADCSR & ADF ) ); /* Wait for end of conversion */ ADCSR &= ~ADF; /* Read register and clear ADF */ Port3 = (( ADDRA >> 6 ) & 0x03ff); /* Shift to an integer in [0..1023]*/
The stack content on entry to the interrupt handler is determined by the H8/3292 interrupt mechanism and the interrupt dispatcher. The content is:H8/3292 interrupt vector address: address of interrupt dispatcher interrupt dispatcher: push r6 mov @RCX interrupt vector address, r6 jsr @r6 pop r6 rte RCX interrupt vector address: address of RCX interrupt handler RCX interrupt handler: save registers needed for interrupt handling handle interrupt restore registers saved return to interrupt dispatcher (rts)
Furthermore, interrupts are disabled on entry to the RCX interrupt handler until the instruction rte is executed by the dispatcher unless the interrupt bit of cc is explicitely cleared by the RCX interrupt handler. Hence, when the I-bit is not cleared, the actions of the RCX interrupt handler is an indivisible, non-interruptable, atomic operation (MOS, chapter 2), since non-maskable interrupts are not used on the RCX.address content sp return to dispatcher sp - 2 r6 of interrupted program sp - 4 cc of interrupted program sp - 6 pc of interrupted program
RCX interrupt handlers can be programmed and installed in assembly language and C. We will use C to illustrate how to install an RCX interrupt handler for the Run button. The following definitions ease installation of an RCX interrupt handler:
The typecast turns the RCX_Vector_Addr into a pointer to a routine that takes no parameters and returns no result. The last define can be used to install e.g. the C routine RunInt as the interrupt handler for the Run button:#define Int_Handler(RCX_Vector_Addr) ( *(void (**)(void))(RCX_Vector_Addr) ) #define IRQ0_Addr 0xfd94 /* RCX IRQ0 Interrupt Vector Address */ #define Run_Button_Interrupt_Handler Int_Handler(IRQ0_Addr)
where the routine RunInt is defined e.g. as follows:Run_Button_Interrupt_Handler = RunInt;
To enable interrupts from the Run button and define the event that triggers the interrupt, we have to access the IRQ device registers:int16 Count; void RunInt (void) { asm("push r0 push r1 push r2 push r3 push r4 push r5 "); /* Increment global counter when Run is pressed */ Count = Count + 1; asm("pop r5 pop r4 pop r3 pop r2 pop r1 pop r0 "); }
To trigger an interrupt by the falling edge of the state of the Run button (when the Run button is pressed) and to enable Run button interrupts, the device registers should be initialized as follows:/* IRQ Sense Control Register and IRQ Enable Register */ #define ISCRaddr 0xffc6 #define IERaddr 0xffc7 #define ISCR *( (byte *) ISCRaddr ) #define IER *( (byte *) IERaddr )
ISCR = 1; IER = 1;
|
|
Figure X The four buttons View, On-Off Prgm and Run. The leJOS Tutorial, (1.2.2006), Controlling the Hardware: Buttons. |
The four buttons are connected to four input lines of the H8/3292 input/output ports. Two of the buttons can also initiate external interrupts. The details are:
| Button | Input port | Address | Bitposition | Interrupt |
|---|---|---|---|---|
| Run | port 4 | 0xffb7 | bit 2 | IRQ 0 |
| OnOff | port 4 | 0xffb7 | bit 1 | IRQ 1 |
| View | port 7 | 0xffbe | bit 6 | no interrupt |
| Prgm | port 7 | 0xffbe | bit 7 | no interrupt |
The bit value obtained on a read is 0 when the button is pressed and 1 when the button is released.
The bit value for each button can be accessed directly from the device registers by bitmanipulation. We will use C to illustrate how button states can be used as input to a C program. We can define the following names to ease access to e.g. the state of the Run button:
The last define makes it possible to use Run as an expression that has the value 1 when the Run button is pressed and 0 when it is released. The value of Run can be used e.g. to stop a loop:#define port4_addr 0xffb7 #define port4 *((volatile byte *) port4_addr) #define Run ! ( port4 & ( 1 << 2 ) )
while ( ! Run ) { ... }
|
|
Figure X The three RCX input ports. The leJOS Tutorial, (1.2.2006), Controlling the Hardware: Sensors. |
The sensors are of two types: passive and active sensors. The passive sensors are the touch and temperature sensors. The active sensors are the light and rotation sensors. From a programming point of view the two types are treated differently.
|
|
Figure X The five standard LEGO sensors. The leJOS Tutorial, (1.2.2006), Controlling the Hardware: Sensors. |
The usage of sensors connected to the input ports requires an understanding of the electronics of the sensors and the input ports. A detailed description of this can be found in Internals of Input Ports and Sensors. Furthermore, it also require knowledge of RCX programming to be able to get values from the sensors connected to the input ports. This is described in the following.
To obtain an input value from a passive sensor we use the A/D converter. For an active sensor like the light sensor we also have to power up an illuminating light emmitting diode (LED) so the red light on the outside of the light sensor is turned on. This is accomplished through one of three output lines of I/O port 6. The rotation sensor also contains LED's that have to be powered up. These LED's are build into the blue LEGO brick and are not visible from the outside.
The three RCX input ports are connected to the channels of the A/D converter and the output lines of I/O port 6 as follows:
| Input Port | A/D Channel | Output Line |
|---|---|---|
| 1 | Analog input pin 2 (AN2) | Port 6, bit 2 |
| 2 | Analog input pin 1 (AN1) | Port 6, bit 1 |
| 3 | Analog input pin 0 (AN0) | Port 6, bit 0 |
The sensor input value is obtained for both types of sensors through an A/D conversion. The device registers of the A/D converter is used to initiate a conversion, to monitor the end of conversion, and to access the resulting converted 10 bit sensor input value. The A/D control/status register is used to start conversion and to poll for the end of conversion. The end of conversion can also be signalled with an A/D end interrupt. The A/D data registers store results of conversions. The data register contains the 10 bit converted value in the 10 most significant bits of a 16 bit word. The data registers are connected to the A/D channels and the converted values can be read at the following addresses:
| Input Port | A/D Channel | Register | Abbreviation | Address |
|---|---|---|---|---|
| 1 | AN2 | A/D data register A | ADDRC | 0xffe4 |
| 2 | AN1 | A/D data register B | ADDRB | 0xffe2 |
| 3 | AN0 | A/D data register C | ADDRA | 0xffe0 |
The A/D control/status register (ADCSR) is an 8 bit device register at address 0xffe8. The bits are used as follows:
| Bit | Name | Abbreviation | Meaning |
|---|---|---|---|
| 7 | A/D End Flag | ADF | should be cleared by program on end of conversion, set by converter to signal end of conversion |
| 6 | A/D End Interrupt Enable | ADIE | 0: interrupt disabled; 1: interrupt enabled |
| 5 | A/D Start | ADST | 0: conversion stopped; 1: start conversion |
| 4 | Scan Mode | SCAN | 0: single mode; 1: scan mode |
| 3 | Clock Select | CKS | 0: slow conversion; 1: fast conversion |
| 2 to 0 | Channel Select | CH2 to CH0 | Selects channel(s) |
The channel select bits are used to select one of the three input ports for conversion (single mode) or select more than one (scan mode), e.g.:
| Input Port | CH2 to CH0 | Mode |
|---|---|---|
| 1 | 010 | single |
| 2 | 001 | single |
| 3 | 000 | single |
| 1,2,3 | 010 | scan |
An example of simple A/D convertion of a single pin value is shown in the module AD.h. The module InputPorts.h contains functions to input both passive and active sensor values. In RCX Programming, Lesson 1 these moduls are used to interprete the light sensor input as different colors.
|
|
Figure X The infrared transmitter and receiver. The leJOS Tutorial, (15.2.2004), Controlling the Hardware: The IR Interface. |
The IR Transmitter/Receiver is based on the on-chip Serial Communication Interface ( SCI, see Section 11 of Hitachi H8/3292 ). The SCI acts as a device controller for the serial infrared communication. Infrared light turned on and off with a frequency of 38.5 kHz is used as a carrier for the serial stream of bits: bit value 0 is represented as a time interval with the infrared light carrier turned on, bit value 1 as a time interval with no infrared light. The frequency of the carrier wave, 38.5 kHz, is provided by the timer output of Timer 1. The infrared transmission can be performed in two modes: Short and long range mode. Pin 0 of Port 4 determines the transmission mode, 1 for short and 0 for long range. The infrared light emitted is not only received by other IR receivers but also by the receiver on the transmitting RCX. This means that simultaneous transmission by two or more, i.e. collision, can be detected by inspection of the received bit stream. The duration of the time interval for a single bit is related to the baud rate selected on the SCI. With a baud rate of 2400 bit/sec the time interval is 417 usec = 1 bit/2400 bit/sec. The communication format used in the serial communication is selected through the device registers of the SCI. A declaration in C of these registers can be seen in the module SCI.h.
The IR transmitter/receiver can be used both program-driven and interrupt-driven as shown by the set of C-routines included in the module IR.h. In RCX Programming, Lesson 3 there is an example of RCX programs that communicate using this module
|
|
Figure X The LCD shows a LEGO man in walking position, the number one to the right of the LEGO man and a motor direction indication above the letter A. The leJOS Tutorial, (1.2.2006), Controlling the Hardware: LCD. |
The LCD screen contains 43 segments. A segment is a figure or a symbol e.g. a dot, an arrow or the legs of a small LEGO man. Each segment can be controlled individually by turning it on or off. This is accomplished through an LCD controller. Communication with the LCD controller takes place on a serial line consisting of two wires. On the RCX these two wires are connected to I/O port 6, bit 5 and bit 6. Reading and writing these two bits is used to control the LCD from the RCX. The on-chip RCX executive uses a protocol on the serial line to implement a number of high-level operations on the LCD: An area of memory contains an LCD buffer with one bit for each segment; the RCX executive routines write to this buffer, and explicit calls to an RCX executive routine, refresh, (see LCD Routines), uses the protocol to update the screen so segments are shown or hidden corresponding to the actual bit values in the LCD buffer. Detailed knowledge of the protocol and the LCD buffer can be obtained from RCX Internals.
To make sounds bit 4 of the output port should be toggled with appropriate time intervals between toggling. E.g. a tone of frequency 500 Hz is produced by repeating:#define P6DDR *((volatile byte *) 0xffb9) #define P6DDR_ROM *((volatile byte *) 0xfd85) #define P6DR *((volatile byte *) 0xffbb) #define bit4 (1 << 4) #define SpeakerHigh P6DR |= bit4 #define SpeakerLow P6DR &= ~bit4 /* Initialize bit4 of port 6 as output. */ P6DDR_ROM |= bit4; P6DDR = P6DDR_ROM;
The toggling of bit 4 can also be controlled by timer output of timer 0.SpeakerHigh; Wait one msec; SpeakerLow; Wait one msec;
|
|
Figure X The three RCX Output Ports A, B and C. From The leJOS Tutorial, (10.2.2004), Controlling the Hardware: Motors. |
The output ports are driven by the current from the 9 V battery power supply. The state of the current flow through the actuator connected to an output port is controlled by the content of the RCX output ports device register at address 0xf000. Each port is controlled by two bits in the 8 bit device register.
| Output Port | A | B | C |
|---|---|---|---|
| Bits | bit 7 and 6 | bit 3 and 2 | bit 1 and 0 |
These output port bitfields can be accessed at the device register address. E.g. to set the state of output port A to 2 can be done in C as follows:
#define OutputPorts *(( volatile byte *) 0xf000 ): #define Amask 0xc0 byte temp; temp = OutputPorts; temp &= ~Amask; temp |= (2 << 6); OutputPorts = temp;
The four possible values of the two bits correspond to four different ways to control the state of the current flow through the actuator. The values 01 and 10 allows the current to flow in either of the two directions. This allows bidirectional control of the current flow. The value 00 disconnect the actuator from the power supply. The value 11 connects the two terminals of the actuator to the same polarity of the power supply. Internals of Output Ports and Actuators contains more details on the connection between the power supply and the output ports.
To make it easier to program the control of the actuators connected to the output ports a simple C-routine can be programmed for each port that sets the current state of the port. E.g. for port A it might look as follows:
A call to the routine Port A sets the state of the corresponding output port to one of the four current states (called Float, OnPos, OnNeg, and Brake) depending on the actual value of the parameter state. Such a set of C-routines are included in the module OutputPorts.h.#define Float 0 #define OnPos 1 #define OnNeg 2 #define Brake 3 void PortA( byte state ) { byte temp; temp = OutputPorts; temp &= ~Amask; temp |= (state << 6); OutputPorts = temp; }
The effect the four states has on an actuator connected to the output port depends on the actuator:
| Output Bits | Motor | Lamp | Flashlight | Sound Element |
|---|---|---|---|---|
| 00 | float, i.e. free running mode | no light | no light | no sound |
| 01 | turn in one direction | light | light/flashing light | one alarmsound |
| 10 | turn in the other direction | light | light/flashing light | the other alarmsound |
| 11 | brake | no light | no light | no sound |
Lets consider a car driven by to motors connected to port A and C and lets call the four current states for Float, OnPos, OnNeg, and Brake as before. State OnPos and OnNeg will make the wheel on the motor turn clockwise or counter-clockwise depending on how the wires are attached to the output ports and the motors. A change from a powered state OnPos or OnNeg to a non-powered state Float or Brake have very different effects on the locomotion of a car. A change to Brake will force the car to stop immediately. A change to Float allows the motors to spin freely and the car will be coasting.
|
|
Figure X Two motors connected to port A and C.
From
The leJOS Tutorial, (10.2.2004), Controlling the Hardware:Motors. |
The C-routines PortA, PortB and PortC allows us to use program-driven control of the output ports. E.g. to make a lamp on port A blink we could repeat the following:
The C-routine can also be used to write C-routines for control of car locomotions. E.g.:PortA(OnPos); Wait one msec; PortA(Float); Wait one msec;
/* Defines the power states that make the wheels drive the car forward and backward. Connections between motors and ports should be change to make these states correspond to the actual car locomotions. */ #define Aback OnNeg #define Aforward OnPos #define Cback OnNeg #define Cforward OnPos void CarCoast ( void ) { PortA(Float); PortC(Float); } void CarBrake ( void ) { PortA(Brake); PortC(Brake); } void CarGoForward ( void ) { PortA(Aforward); PortC(Cforward); } void CarGoBackward ( void ) { PortA(Aback); PortC(Cback); } void CarSpinClockwise ( void ) { PortA(Aforward); PortC(Cback); } void CarSpinCounterClockwise ( void ) { PortA(Aback); PortC(Cforward); }
If the state changes on an output port happen fast enough, e.g. OnPos, Float, OnPos, Float, ... with a 1 msec duration of each state, the effect on a lamp is that it will not shine as bright as when powered all the time. This mode of actuator control is called puls width modulation (PWM). Each power-on state is called a puls and the duration of the puls is called the width of the pulse. The energy transfered to an actuator can be controlled by varying the puls width and the pattern of pulses. To implement PWM output port control, we can use the T0 timer of the H8/3292 to provide timer interrupts with a period of e.g 1 msec. These interrupts can be used to call a C-routine that provide a regular patterns of state changes of an output port. The module MotorControl.h uses PWM control to drive the output ports A and C. Each output port can be driven at 16 different energy levels provided by 16 different puls patterns. In RCX Programming, Lesson 2 there is an example of a C program that drives a car using routines in this module.
In Madvick and Donovan, Operating Systems, 1974, an executive system is described as follows:"As computers became more complex, especially with regard to I/O device management, executive systems were developed that permanently resided in memory and provided Input/Output Control Services (IOCS) for user jobs". This fits with the function of the ROM based system on the RCX. This is the reason for calling it an executive. Others call a similar system an On-board Monitor.
wherepacket = header request/reply trailer
The checksum is obtained as the least significant byte of the sum of the bytes in the request/reply.header = 0x55 0xff request/reply = bytesequence trailer = checksum
A request is thus represented as a sequence of bytes. The first byte is the request code, the following bytes contain the request data. A reply has a similar structure with the first byte being the reply code, the following bytes being the reply data. The reply code is the bit complemented value of the request code sent. For each request there are two request codes, the difference between the two codes is the value of bit 4 in the byte. This is a sequence control bit: The executive only executes the first of a sequence of requests with identical request codes, the second and beyond are not executed. The reply sent to the second request and beyond is the same as that sent to the first. To make sure the same request is executed twice in a row by the executive, use alternate sequence control bit values. This is needed in a sequence of DownloadBlock requests.
Now follows a detailed description of each request/reply. For each request/reply the two request codes/reply codes are given (in hex) together with the meaning and representation of the request data/reply data.
| Request | Request codes | Request data | Reply codes | Reply data |
|---|---|---|---|---|
| Alive | 10/18 | none | ef/e7 | none |
| GetVersions | 15/1d | Key | ea/e2 | ROMVersion, ProgramVersion |
| EnterDownloadMode | 65/6d | Key | 9a/92 | none |
| BeginDownload | 75/7d | ProgramEntryPoint, ProgramChecksum, Zero | 8a/82 | Result |
| DownloadBlock | 45/4d | BlockSequenceNumber, BlockLength, DataBlock, BlockChecksum | ba/b2 | Result |
| RunProgram | a5/ad | RunKey | 5a/52 | Text |
- 1 : not enough memory
- 2 : bad block format
- 3 : checksum error in this block
- 4 : program checksum error
- 6 : not in download mode
The program inputs a request as a sequence of raw hexadecimal represented bytes. This is sent to the RCX executive. Then the program waits for a reply. After a while either a correct reply has been received or a failure has occurred. The program outputs either a reply as a sequence of raw hexadecimal represented bytes or the course of failure.
To check the liveliness of the connection and the RCX, we may use the program as follows:
The Alive request is sent as the raw request code 10. The reply is ef, signalling that things are ok.RCX_Request_Reply 10 0000: ef
The versions of the programs running on the RCX are obtained by:
No application program is running and the version of the executive is 3.1.RCX_Request_Reply 15 1 3 5 7 b 0000: ea 00 03 00 01 00 00 00 00
Now we want to download and run the following simple assembly language program - notice how the mandatory text is included by means of a .string directive in the data section:
First we have to assemble it into an absolute program e.g. as hexadecimal bytes:.section .text .align 1 .global __start __start: mov.w @0,r0 jsr @r0 .section .data .string "Do you byte, when I knock?" .end
Then we have to calculate the ProgramChecksum and the BlockChecksum.mov.w @0,r0 6b 00 00 00 jsr @r0 5d 00 Do 44 6f 20 you 79 6f 75 20 byte, 62 79 74 65 2c 20 when 77 68 65 6e 20 I 49 20 knock? 6b 6e 6f 63 6b 3f
To download the resulting program to the memory of the RCX we proceed
as follows:
EnterDownloadMode:
BeginDownload, ProgramEntryPoint = 8000, ProgramChecksum = 09a8, Zero = 0:RCX_Request_Reply 65 1 3 5 7 b 0000: 9a
DownloadBlock, BlockSequenceNumber = 0, BlockLength = 0022, DataBlock = 6b 00 ... 3f 00 00, BlockChecksum = a8:RCX_Request_Reply 75 00 80 a8 09 00 0000: 8a 00
RunProgram, RunKey = 4c 45 47 4f ae (hex):RCX_Request_Reply 4d 00 00 22 00 6b 00 .... 3f 00 00 a8 0000: b2 00
The reply contains the hexadecimal represented ASCII values for the text "Just a bit off the block!". So things are ok and the program is running. Not for long, however. The two instructions of the program make an indirect jump through the reset vector at address 0. This will give back the control to the executive.RCX_Request_Reply a5 4c 45 47 4f ae 0000: 5a 4a 75 73 74 20 61 20 62 69 74 20 6f 66 66 20 0010: 74 68 65 20 62 6c 6f 63 6b 21
As a simple example we will start with a routine for multiplication of 16-bit signed integers. It is available in the executive at the address 0x0130; this means that the multiplication routine can be called in assembly as a subroutine:
The two operands are passed to the subroutine in registers r5 and r6, the result is returned in r6. This means that multiplication of e.g. 51 and 72 can be carried out in assembly as:jsr @0x0130
The value of r6 is 3672 = 51*72 on return from the subroutine.mov.w #51, r5 mov.w #72, r6 jsr @0x0130
In a C-program we can wrap this assembly call into a C function as follows:
This C function can be activated as usual in a C-program:int16 imul( int16 a, int16 b) { int res; asm("mov.w %1,r5 mov.w %2,r6 jsr 0x0130 ; call imul mov.w r6,%0 ": "=r" (res) : "r" (a), "r" (b) : "r0", "r1", "r5", "r6" ); return res; }
C wrappers, like the one for the multiplication routine, can be programmed for the executive routines to ease access to the executive services.int16 p; ... p = imul(51,72);
A number of C wrappers can be collected and placed together with data types, constants, and global variables in an interface definition or header file , e.g. RCX_RTE.h. This simple interface also contains the main data types for the H8/300, like byte and word, the mandatory text "Do you byte, when I knock?" and a routine to reset the RCX. The interface can be included in the text of a C-program:
This simple interface to the RCX executive is an example of a run-time environment that can be based on the RCX executive. In the following the services provided for access to the LCD in this interface will be described in detail.#include "RCX_RTE.h"
| LCD routine | Description | call address | parameter names and type |
|---|---|---|---|
| refresh | updates screen with LCD buffer contents | 0x27c8 | no parameters |
| clear | clear screen | 0x27ac | no parameters |
| show_icon | make icon visible | 0x1b62 | icon (16-bit) |
| hide_icon | hide icon | 0x1e4a | icon (16-bit) | show_number | an integer value is shown according to the format and scale parameters | 0x1ff2 | format (16-bit), value (16-bit), scalecode (16-bit) |
The first parameter to the routines is passed in register r6, the remaining parameters are passed on the stack: the third parameter is the first to be pushed onto the stack, then the second parameter is pushed onto the stack. The parameters have the following meaning:
| 16-bit code | Describtion |
|---|---|
| 0x3006 | standing figure |
| 0x3007 | walking figure |
| 0x3008 | sensor 0 view selected |
| 0x3009 | sensor 0 active |
| 0x300a | sensor 1 view selected |
| 0x300b | sensor 1 active |
| 0x300c | sensor 2 view selected |
| 0x300d | sensor 2 active |
| 0x300e | motor 0 view selected |
| 0x300f | motor 0 backward arrow |
| 0x3010 | motor 0 forward arrow |
| 0x3011 | motor 1 view selected |
| 0x3012 | motor 1 backward arrow |
| 0x3013 | motor 1 forward arrow |
| 0x3014 | motor 2 view selected |
| 0x3015 | motor 2 backward arrow |
| 0x3016 | motor 2 forward arrow |
| 0x3018 | datalog indicator |
| 0x3019 | download in progress |
| 0x301a | upload in progress |
| 0x301b | battery low |
| 0x301c | short range indicator |
| 0x301d | long range indicator |
| 0x3020 | all segments |
Repeated calls with the codes 0x3018, 0x3019, and 0x301a make a simple animation on the screen. This can be used to indicate a time consuming process in progress.
The sign position can show a minus (-) or be empty. The other five positions can show the decimal digits 0,1,...9 , a minus (-), or be empty. Between digit3 and digit2, or between digit2 and digit1, or between digit1 and digit0, a decimal point can be shown as a dot. The parameter format controls how the 16-bit value passed as the second parameter is interpreted and made visible on the screen.sign digit3 digit2 digit1 digit0 digit
| Format | Meaning |
|---|---|
| 0x3001 | the 16-bit value is interpreted as a signed integer and shown as up to four decimal digits in positions 3, 2, 1, 0 with no leading zeros. If the value is less than -9999, -9999 is shown, if the value is greater than 9999, 9999 is shown |
| 0x3017 | if the 16-bit value is in the range 0..9 it is shown in the digit position. Otherwise nothing is shown. |
| 0x301f | the 16-bit value is interpreted as an unsigned integer and shown in positions 3, 2, 1, 0 with leading zeros. If the value is greater than 9999, 9999 is shown. |
| Scalecode | Scalefactor |
|---|---|
| 0x3002 | 1 |
| 0x3003 | 0.1 |
| 0x3004 | 0.01 |
| 0x3005 | 0.001 |
These executive LCD routines can be wrapped into C routines. Examples of such wrapped C routines have been included in RCX_RTE.h with names as in the table of the LCD executive routines prefixed with lcd_, lcd_refresh, lcd_clear,.... (see RCX_RTE.h description). Each routine ends with an explicit call to refresh to update the screen immediately after the changes have been made to the LCD buffer. To ease the use even further, also specialized calls to show_number have been included in RCX_RTE.h, such as lcd_show_int16 and lcd_show_digit. This shows how specialized routines can be based on the general routines provided by the executive.
This command performs the translation of the assembly program into an S-record formatted RCX program in two steps: the first step translates the assembly program into an object module asm_reset.o, the second step transforms the object module into a sequence of S-records in asm_reset.srec. The two steps performed by the command are contained in the following Makefile:make asm_reset.srec
Here, as is a cross-assembler, not the native assembler on the UNIX host machine ; ld is a cross-linker. The linker works under the explicit control of the link script contained in the file asm_rcx.lds given after the option T. The linker script in asm_rcx.lds defines the transformation from the object file into the S-records. This file looks as follows:# Makefile for H8/300 cross translation of assembler programs. # Path to assembler (as) and linker (ld). BINDIR = /users/kursus/dArk/solaris/h8300-hitachi-hms/bin/ AS = $(BINDIR)as LD = $(BINDIR)ld # Options for linker. LFLAGS = -Tasm_rcx.lds # Entries. # $< and $@ expands to the actual file name that matches the # right hand side and the left hand side of : (colon). %.o: %.s $(AS) $< -o $@ %.srec: %.o $(LD) $(LFLAGS) -o $@ $<
/* * asm_rcx.lds * * GNU ld script for mapping an assembled object module into * an S-record represented absolute H8/300 program. The sections of * the object module is mapped into the memory of the RCX starting at * the load address 0x8000. The length of the program should not exceed * 0x6fff because the address 0xf000 is used as device register. * The program entry point is __start. * */ OUTPUT_FORMAT(srec) OUTPUT_ARCH(h8300) ENTRY(__start) MEMORY { mem : ORIGIN = 0x8000, LENGTH = 0x6fff } SECTIONS { .text : { *(.text) } > mem .data : { *(.data) } > mem }
The translation and transformation performed by make asm_reset.srec results in the following sequence of five S-records contained in the file asm_reset.srec:
The first S0 record contains the name of the file as ASCII characters (r=72, e=65, ...). The terminating S9 record contains the entry point of the H8/300 program, 0x8000. The three remaining S1 records contains the native code, each byte is represented as a two digit hexadecimal number. The load address of the first S1 record is 0x8000, that is where the first byte of the program goes.S011000061736D5F72657365742E7372656350 S10980006B0000005D00AE S1188006446F20796F7520627974652C207768656E2049206B6B S10A801B6E6F636B3F000070 S90380007C
In this program the reset is accomplished through a call to the C routine RCX_Reset in RCX_RTE.h (see RCX_RTE.h description). This program can be compiled into an object module and then transformed into a sequence of S-records in a way similar to the cross-assembly process described for assembly language programs. This time the UNIX command is:#include "RCX_RTE.h" void _start(void) { RCX_Reset(); }
The result is an S-record formatted native program reset.srec for the RCX. The following Makefile was used:make reset.srec
This Makefile can also be used to compile a C-program into an object modul with the command:# Makefile for H8/300 cross compilation of C and assembler programs. # Path to C compiler (gcc), assembler (as) and linker (ld). INSTDIR = /users/legolab/RCX BINDIR = $(INSTDIR)/`uname -s`/h8300-hitachi-hms/bin/ CC = $(BINDIR)gcc AS = $(BINDIR)as LD = $(BINDIR)ld RCXDOWNLOAD = $(INSTDIR)/`uname -s`/bin/RCX_Download # Options for C compiler and linker. CFLAGS = -O2 -Wall -I$(INSTDIR)/include LFLAGS = -T$(INSTDIR)/Manual.dir/rcx.lds # Entries. # $< and $@ expands to the actual file name that matches the # right hand side and the left hand side of : (colon). %.o: %.c $(CC) $(CFLAGS) -c $< %.o: %.s $(AS) $< -o $@ %.s: %.c $(CC) -S $(CFLAGS) $< %.srec: %.o $(LD) $(LFLAGS) -o $@ $< %.send: %.srec $(RCXDOWNLOAD) $<
To compile a C-program into an assembly language program use the Makefile as follows:make reset.o
This is useful when there is a need to inspect the symbolic H8/300 code generated by the cross-compiler.make reset.s
The link script rcx.lds specified in the T option of the linker is:
This link script controls the mapping from the object modul into an S-record formatted native program for the RCX./* * rcx.lds * * GNU ld script for mapping a C compiled object module into * an S-record represented absolute H8/300 program. The sections of * the object module is mapped into the memory of the RCX starting at * the load address 0x8000. The length of the program should not exceed * 0x6fff because the address 0xf000 is used as device register. * The program entry point is __start. * */ OUTPUT_FORMAT(srec) OUTPUT_ARCH(h8300) ENTRY(__start) MEMORY { mem : ORIGIN = 0x8000, LENGTH = 0x6fff } SECTIONS { .text : { *(.text) *(.rodata) } > mem .data : { *(.data) } > mem .bss : { __bss_start = . ; *(.bss) *(COMMON) __end = . ; } > mem /DISCARD/ : { *(.vectors) } }
The program RCX_Download.c goes through all the steps needed to download and start the program in the file given by the filename. The infrared transmitter/receiver should be connected to a serial port given by a name defined in the program by the constant text named DEFAULT_RCX_IR. Change this if needed or use the environment variable RCX_IR to override the default setting.RCX_Download
Brian W. Kernighan, Dennis H. Ritchie, The C Programming Language, Second edition,Prentice Hall, 1988.
[MOS]
Andrew S. Tanenbaum:
Modern Operating Systems, Prentice Hall, 1992.
A lot of the information in this manual has been collected from RCX Internals, LEGO MindStorms Internals, and the legOS description.