Lego Controller

***NOTE*** This is a quick reference for the Lego controller. For a more detailed description of the Lego controller see Lego manual. You should also first read and understand the operation of the GPIO devices JP1/JP2.

The Lego Controller can be plugged into either the JP1 or JP2 40-pin expansion headers, and is controlled by reading or writing to the GPIO port. The first 10 bits (0 to 9) are used to control up to 5 motors, turning them ON/OFF and changing their direction. Bits 10,12,14,16,18 are used to enable up to 5 sensors. Bits 27 to 30 have a dual function. They can be used to read sensor data or indicate a state value of high or low depending on the threshold value. Bit 31 is used to determine the state value of sensor 5. Bits 23 to 26 are used to load a threshold value, depending on which sensor is selected. Bits 11,13,15,17 and 19 are used as acknowledge hand shaking bits for each of the sensors in polling mode. The board also features 5 HEX displays which display the values being read by the sensors.

Since the Lego controller is controlled through a single GPIO port, certain bits will be configured as both inputs and outputs. When reading inputs, it will thus be necessary to use masking to get valid data. Similarly, when writing to the outputs, care will have to be taken to keep any bits you do not want changed the same.

DeviceLego Controller: connected via JP1 or JP2
Input/Outputboth
Address BaseJP1: 0xFF200060; JP2: 0x0xFF200070
Address Map: Value Mode
AddressR/WDescription
baseR/WData Register:
Description:Sensor Values and control bitsSensor ControlMotor Control
sensor5 Sensor ValueThreshold value Load Threshold ModeUnusedReady sensor4Sensor4Ready sensor3Sensor3Ready sensor2Sensor2Ready sensor1Sensor1Ready sensor0Sensor0Motor4Motor3Motor2Motor1Motor0
Bit:3130292827262524232221201918171615141312111098 76543210
Usage:- sensor read value-----state/
value
-valid/
not valid
on/
off
valid/
not valid
on/
off
valid/
not valid
on/
off
valid/
not valid
on/
off
valid/
not valid
on/
off
for/
rev
on/
off
for/
rev
on/
off
for/
rev
on/
off
for/
rev
on/
off
for/
rev
on/
off
base+4WDirection Register: 0x07f557ff
Bits 26 downto 21 and 18,16,14,12,10 downto 0 must be set to 1's outputs
Bits 31 downto 27,19,17,15,13,11 must be set to 0's inputs.
Bit 19,17,15,13,11 are used to detect if sensor data is valid. Sensor data is valid when low
Note: load=0, don't-load=1; state=0, value=1; forward=0, reverse=1; on=0, off=1
Note2: the actual direction of a motor depends on the polarity that you connect it
Address Map: State Mode
AddressR/WDescription
baseR/WData Register:
Description:Sensor Values and control bitsSensor ControlMotor Control
State4State3State2State1State0Threshold valueLoad ThresholdModeUnusedReady sensor4Sensor4Ready sensor3Sensor3Ready sensor2sensor2Ready sensor1Sensor1Ready sensor0Sensor0Motor4Motor3Motor2Motor1Motor0
Bit:3130292827262524232221201918171615141312111098 76543210
Usage:below/
above
below/
above
below/
above
below/
above
below/
above
threshold write valueload/
don't load
state/
value
-valid/
not valid
on/
off
valid/
not valid
on/
off
valid/
not valid
on/
off
valid/
not valid
on/
off
valid/
not valid
on/
off
for/
rev
on/
off
for/
rev
on/
off
for/
rev
on/
off
for/
rev
on/
off
for/
rev
on/
off
base+4WDirection Register: 0x07f557ff
Bits 18,16,14,12,10 downto 0 must be set to 1's outputs.
Bits 31 downto 27,19,17,15,13,11 must be set to 0's inputs.
base+8WInterrupt Mask Register enables interrupts for each pin (the corresponding pins should be configured as input). Eg., set to 0xf8000000 to allow interrupts on any sensor
base+12R/WEdge Capture Register, writing a 1 clears the corresponding bit. Writing 0xFFFFFFFF clears all bits.
Note: at or above=1, below=0; load=0, don't-load=1; state=0, value=1; forward=0, reverse=1; on=0, off=1
Note 2: the actual direction of a motor depends on the polarity that you connect it
Interrupts for State Mode
EnableSet bits in Interrupt Mask Register that correspond to data bits you want to interrupt on
TriggeredNegative edge: When an interrupt enabled input data bit changes from value of '1' to a value of '0' (From "above" to "below" threshold)
IRQ LineJP1: 11; JP2: 12
AcknowledgeWritng 0xFFFFFFFF to Edge Capture Register clears it
Reference Lego Controller Manual

Hardware Setup

Breakout box

The sensor interface works in two modes: value mode and state mode.

Sensors: Value Mode

Value mode is the default. In Value mode, one sensor is selected at a time using bits 18,16,14,12,10 then the 4-bit value of the selected sensor can then be read on bits 30 downto 27. In value mode sensors can only be read one at a time. Reading a sensor value requires two steps:

  1. Enable a sensor: tell the Lego controller which sensor you want to read by writing to the bits of 18,16,14,12,10. Write a 0 for the corresponding sensor you want to enable (write 1 for the rest). At the same time you should have Mode set to "Value" and Load Threshold set to "Don't Load"
  2. Read the sensor: read the bits 30 downto 27 to get the current value of the selected sensor. In order to have valid data the corresponding sensor ACK bit 19,17,15,13,11 must be low.If it is not low data at 30 downto 27 may not be valid

Sensors: State Mode

In State mode, 4-bit threshold values are uploaded for each sensor. Bits 18,16,14,12,10 are used to select the sensor and bits 26 downto 23 are used to write the threshold value. Loading threshold values must be done in Value mode. When the mode is switched to State mode, bits 31 downto 27 will display the current "state" of all 5 sensors. When a sensor reads a value greater than or equal to the threshold it will set its corresponding bit to a 1, otherwise that bit will be 0. By using the interrupt feature of the GPIO ports you can set an interrupt to trigger when a sensor decreases past its threshold value (negative edge).

In State mode, all 5 sensors can be read at once, but each sensor only returns one bit indicating whether it is: at/above threshold or below threshold. Threshold values for each sensor need to be loaded into the Lego controller beforehand. Threshold values can only be loaded one at a time. Loading a threshold value requires three steps:

  1. Enable sensor for loading: tell the Lego controller which sensor will get the threshold value by writing to bits 18,16,14,12,10. Write a 0 for the corresponding sensor that you want to enable (write 1 for the rest). At the same time you should have Load Threshold set to "Load" and Mode set to "Value"
  2. Write threshold value: write the 4-bit threshold value to bits 26 downto 23.
  3. Disable sensor for loading: tell the Lego controller the threshold value has been loaded by disabling all sensors and setting Load Threshold to "Don't Load".
Once all the sensors have been given a threshold value you can set Mode to "State" by writing to bit 21. Then to check the state of the sensors, read bits 31 downto 27. A value of 1 means the corresponding sensor is at/above its threshold value and a value of 0 means its below its threshold.

Interrupts (in State Mode)

When using the Lego controller in State Mode we can set interrupts to trigger any time a sensor value has passed its threshold value. To do this we use the interrupt feature of the GPIO. Before enabling interrupts make sure that the sensors are setup for State Mode. To enable interrupts for the sensors do the following:
  1. Enable Interrupts for each desired sensor using the interrupt mask register. This means setting bits 31 downto 27 of the IMR appropriately.
  2. Enable interrupts for IRQ11 or IRQ12 using ctl3.
  3. Enable interrupts globally using ctl0.
In the interrupt handler routine you can check which sensor triggered the interrupt by reading the edge capture register.

NOTE: It is possible for two sensors to interrupt at once. Also, a sensor that is not enabled for interrupts will still cause its corresponding bit on the edge capture register to go high.

Remember to clear the edge capture register before exiting the interrupt hander routine.

Notes on Using the Lego Controller

The Lego Controller we are interfacing with views its inputs as coming from GPIO port 0 or 1. Bits 9 downto 0 controls up to 5 motors, bits 18,16,14,12,10 controls up to 5 sensors, bits 19,17,15,13,11 are sensor acknowledge bits and bits 30 downto 27 reads the sensor data. However, from the perspective of the software, you have only a single port available to control the device, as described above. This means you must exercise great caution when using the device, specifically when controlling the sensors.

One possible strategy to manage sensor and motor control bit values is to designate a register that will hold the state of the motors and sensors. Modify this register to control the motors, and then write that register to the Lego controller.

Assembly Example: Assuming Lego controller plugged into JP1, turn motor0 on, forwards

  
  .equ ADDR_JP1, 0xFF200060   # Address GPIO JP1
  movia  r8, ADDR_JP1     

  movia  r9, 0x07f557ff       # set direction for motors to all output 
  stwio  r9, 4(r8)
  
  movia	 r9, 0xfffffffc       # motor0 enabled (bit0=0), direction set to forward (bit1=0) 
  stwio	 r9, 0(r8)	

Assembly Example: Assuming Lego controller plugged into JP2, read sensor3

  .equ ADDR_JP2, 0xFF200070   # address GPIO JP2

   movia  r8, ADDR_JP2

   movia  r10, 0x07f557ff     # set direction for motors and sensors to output and sensor data register to inputs
   stwio  r10, 4(r8)

 loop:
   movia  r11, 0xfffeffff     # enable sensor 3, disable all motors
   stwio  r11, 0(r8)
   ldwio  r5,  0(r8)          # checking for valid data sensor 3
   srli   r6,  r5,17          # bit 17 is valid bit for sensor 3           
   andi   r6,  r6,0x1
   bne    r0,  r6,loop        # wait for valid bit to be low: sensor 3 needs to be valid
 good:
   srli   r5, r5, 27          # shift to the right by 27 bits so that 4-bit sensor value is in lower 4 bits 
   andi   r5, r5, 0x0f

Assembly Example: Assuming Lego controller is plugged into JP2, Trigger interrupt when the Sensor3 value becomes greater than a threshold value of 0x5 (using state mode)

  .equ ADDR_JP2, 0xFF200070     # address GPIO JP2
  .equ ADDR_JP2_IRQ, 0x1000      # IRQ line for GPIO JP2 (IRQ12) 

   movia  r8, ADDR_JP2         # load address GPIO JP2 into r8
   movia  r9, 0x07f557ff       # set motor,threshold and sensors bits to output, set state and sensor valid bits to inputs 
   stwio  r9, 4(r8)

# load sensor3 threshold value 5 and enable sensor3
 
   movia  r9,  0xfabeffff       # set motors off enable threshold load sensor 3
   stwio  r9,  0(r8)            # store value into threshold register

# disable threshold register and enable state mode
  
   movia  r9,  0xfadfffff      # keep threshold value same in case update occurs before state mode is enabled
   stwio  r9,  0(r8)
 
# enable interrupts

    movia  r12, 0x40000000       # enable interrupts on sensor 3
    stwio  r12, 8(r8)

    movia  r8, ADDR_JP2_IRQ    # enable interrupt for GPIO JP2 (IRQ12) 
    wrctl  ctl3, r8

    movia  r8, 1
    wrctl  ctl0, r8            # enable global interrupts 
 
    LOOP:
    br LOOP

Assembly Example: Using JP2, Check if sensor 2 triggered the interrupt

.equ ADDR_JP2_IRQ, 0x1000            # IRQ line for for GPIO JP2 (bit 12) 
.equ ADDR_JP2_Edge, 0xFF20007C      # address Edge Capture register GPIO JP2 

  rdctl et, ctl4                    # check the interrupt pending register (ctl4) 
  movia r2, ADDR_JP2_IRQ    
  and	r2, r2, et                  # check if the pending interrupt is from GPIO JP2 
  beq   r2, r0, exit_handler    

  movia r2, ADDR_JP2_EDGE           # check edge capture register from GPIO JP2 
  ldwio et, 0(r2)
  andhi r2, et, 0x2000              # mask bit 29 (sensor 2)  
  beq   r2, r0, exit_handler        # exit if sensor 2 did not interrupt 

For further sample code go to the Lego Controller home page.