Sunday, April 17, 2011

MOTOR CONTROLLER TO OPEN8 INTERRUPT INTERFACE


The Interrupt from the motor controller to the CPU needs to be high for 1 clock cycle. There is not interrupt acknowledge signal from the Open8 CPU that can turn off the interrupt after 1 clock signal. If the motor controller interrupt is more than one clock cycle, The CPU interprets it as a separate request. So there is a need for a moderator that 
  • Receives an interrupt request from the motor controller
  • Responds to the interrupt by sending a signal to the CPU interrupt line which is high for exactly one clock cycle. 
  • After sending the interrupt request to the CPU, sends an interrupt acknowledge signal to the motor controller. 

This moderator is Int_req_ack module.


The Int_req_ack module has a 2 bit counter which is initialized to “00”.  When the motor interrupt goes high, the counter is incremented by 1 every clock cycle and the interrupt_CPU line goes high. Since we need the interrupt_CPU line to be high for exactly one clock signal, the counter is reset when it reaches “01”. When the counter value goes to “01”, the interrupt_CPU line goes low and an acknowledge signal (int_ack) is sent to the motor controller. The int_ack signal to the motor controller, pulls down the motor_interrupt signal. This is sensed by the int_req_ack module and resets the counter to “00”.

(a 1 bit counter would have sufficed. Made it two bits so that additional functionalities can be added if required)


--
Abishek Ramdas
NYU Poly

MOTOR CONTROLLER BLOCK DIAGRAM

SPECIFICATION:
The motor  controller is provided with a control word from the open8 micro controller. The control word is 8 bits wide, bits 3 down to 0 represents the number of steps that is to be moved. Bits 5,4 selects the motor that is to be rotated and bit 6 is used to select the direction of rotation (forward or reverse). Bit 7 is used for selecting between interrupting or not interrupting the microcontroller after task is completed.

Contorl word (8 bits) - control_word_reg
1.Bits 3 down to 0 – Number of steps to be rotated (step_counter)
  • “1111” - 15 steps (example)
2.Bits 5 down to 4 – (select) The Motor that is to be rotated (Motor_select)
  • Control_word(5) = 1, left motor is selected
  • Control_word(4) = 1, right motor is selected
  • Control_word(5,4) = “11”, both motors are selected
  • Control_word(5,4) = “00”, No motor is selected

3.Bit 6 – Direction of rotation of the selected motor(s) (Motor_direction)
  •  Control_word(6) =  0, forward direction of rotation
  •  Control_word(6) =  1, reverse direction of rotation
4.Bit 7 – Interrupt upon task completion
  •  Control_word(7) = 1, interrupt the MC upon completion of task
  •  Control_word(7) = 0, do not interrupt the MC upon completion of task, execute the previous control word again.
Two modes of operations:

Depending on the bit 7, the motor controller can operate in
       1.autonomous mode
       2.slave mode
Autonomous mode – control_word(7) = '0'
 The motor controller, loads the control word that is available in the control_word_register after completing a task and continues to execute it. It doesnt interrupt the micro controller after completion of the task. This frees the MC from servicing the motor controller when there is no need for it.

Slave mode – control_word(7) = '1'
 The motor controller interrupts the MC after completion of the task. The microcontroller can load a new control word into the motor controller upon interrupt. This gives a greater controllability in terms of the number of steps to be rotated. 

MOTOR CONTROLLER BLOCK DIAGRAM


WRITING INTO THE CONTROL WORD REGISTER (enable, control_word, wr_en)
The control word is decoded by the motor controller. The control word is written into the control register of the motor controller by selecting the motor controller using the enable signal, loading the control_word onto the control word line and writing into the register by pulling up the write enable (wr_en) line. The motor controller starts executing the control word loaded immediately after it is loaded.   


INTERRUPTING THE CPU (task_completed, int_ack)
If the motor controller is posed to interrupt the CPU after it has completed its operation, The task_completed line goes high after completing its task. The motor controller expects an interrupt acknowledge signal. Upon the receipt of interrupt acknowledge signal, the task_completed line goes low and the motor controller waits for the control word to be loaded onto the control line. If it is not posed to interrupt the CPU, the task_completed remains low and doesnt interrupt.


INTERFACE WITH THE MOTOR(motor_output1, motor_output2, motor_feedback)
The motor controller can be interfaced with two stepper motors. The motor circuitry is expected to provide a signal upon rotation of the motor after each step. This signal is motor_feedback. The reception of this signal means that rotation of the motor by one step is complete. The 4 bit patterns to the two motors are provided by the motor_output1 and motor_output2 signal.


--
Abishek Ramdas
NYU Poly

MOTOR CONTROLLER

The motor controller is the interface to the stepper motor. Stepper motor has four coils. The coils of the stepper motor are to be energized as follows for it to rotate forward.
Stepper motor operation








So to rotate the stepper motor in the “forward direction”, the sequence 1100 is to be right shifted by one bit for each step. A step is defined as the linear distance traveled when the sequence is shifted right by one bit. To rotate the stepper motor in the “reverse direction”, the sequence 1100 is to be shifted left by one bit for each step. Thus the operation involving rotation of the stepper motor is shifting the sequence 1100 right or left onto the coils of the stepper motor. An encoder provides feedback upon completion of one step rotation. The feedback signal is used as an indicator to shift the next pattern in.


Step Angle:
There are 4 steps in 360 degrees. Hence the step angle is 90 degrees
step angle = 360/4 = 90
if the diameter of the wheel is 5 cm, the distance moved in one step is approx (2*pi*r/4) =  4 cms.


Thus when both the wheels are rotated by a step, the motor moves forward by 4 cms.

Turning:
The robot has two wheels. The wheels are connected to the stepper motor. To move the robot forward, both wheels are to be rotated at the same time in the forward direction. To turn the robot right we can either
1.Rotate the left wheel while keeping the right wheel stationary.
2. Rotate the left wheel forward and right wheel backward (tight turn).
Thus using these maneuvering techniques, we can make the robot move in forward, reverse directions and also make it turn left and right. Tight turn is not implemented.

Angle of Turn per step
The method of turning is rotate one wheel while keeping the other stationary.
The width of the robot is taken to be 15 cm.
The linear distance moved per step is 4cm
we know s = r * Ɵ
4 = 15 *  Ɵ =>  Ɵ = 15 degrees

Thus for turning, rotate one wheel and do not rotate the other. each step turns the robot by 15 degrees.



SPECIFICATION:
The motor  controller is provided with a control word from the open8 micro controller. The control word is 8 bits wide, bits 3 down to 0 represents the number of steps that is to be moved. Bits 5,4 selects the motor that is to be rotated and bit 6 is used to select the direction of rotation (forward or reverse). Bit 7 is used for selecting between interrupting or not interrupting the microcontroller after task is completed.

Contorl word (8 bits)
1.Bits 3 down to 0 – Number of steps to be rotated (step_counter)
1.“1111” - 15 steps (example)
2.Bits 5 down to 4 – (select) The Motor that is to be rotated (Motor_select)
1.Control_word(5) = 1, left motor is selected
2.Control_word(4) = 1, right motor is selected
3.Control_word(5,4) = “11”, both motors are selected
4.Control_word(5,4) = “00”, No motor is selected
3.Bit 6 – Direction of rotation of the selected motor(s) (Motor_direction)
1.Control_word(6) =  0, forward direction of rotation
2.Control_word(6) =  1, reverse direction of rotation
4.Bit 7 – Interrupt upon task completion
1.Control_word(7) = 1, interrupt the MC upon completion of task
2.Control_word(7) = 0, do not interrupt the MC upon completion of task, execute the previous control word again.

Two modes of operations:

Depending on the bit 7, the motor controller can operate in
       1.autonomous mode
       2.slave mode
Autonomous mode – control_word(7) = '0'
The motor controller, loads the control word that is available in the control_word_register after completing a task and continues to execute it. It doesnt interrupt the micro controller after completion of the task. This frees the MC from servicing the motor controller when there is no need for it.

Slave mode – control_word(7) = '1'
The motor controller interrupts the MC after completion of the task. The microcontroller can load a new control word into the motor controller upon interrupt. This gives a greater controllability in terms of the number of steps to be rotated. 

DESCRIPTION AND OPERATION OF THE MOTOR CONTROLLER
The entity used to interface with the motor is shown below

entity motor_interface is
  port (
    enable                 : in  std_logic;
    motor_feedback : in  std_logic;
    rst                       : in  std_logic;
    control_word     : in  std_logic_vector(7 downto 0);
    wr_en                : in  std_logic; 
    motor_output1   : out std_logic_vector(3 downto 0);
    motor_output2   : out std_logic_vector(3 downto 0);
    task_completed  : out std_logic;
    int_ack               : in  std_logic);
end motor_interface;


Description:
The motor_feedback is the feedback signal from the motor encoders after it has rotated a step. Rst is the reset signal, control_word is the control word loaded from the micro controller. Whenever enable signal is made high, the control word is loaded into the internal registers. The motor_output1 and motor_output2 are the wires connected to the coils of the stepper motor through proper driving circuitry.  The task_completed output is used to interrupt the micro controller upon task completion.

Operation:
The motor controller has an internal control_word_register. This control word register is initialized to “00111111” . This means that the robot moves forward. The is a step counter which keeps track of the number of steps moved. The model used here is the control word loads the pattern (“1100”) onto the coils of the motor. The motor rotates by a step and sends a feed back signal (motor_feedback) upon completion. Upon receiving the feedback signal, the motor controller decrements the step counter by 1, loads the next shifted pattern.

Reset
Upon reset, the control word is set to “00111111”. The step counter is set to control_word(3 downto 0)=“1111”(15 steps). The Motor_select is set to control_word(5 downto 4) = “11”(select both motors). The Motor_direction is set to control_word(6) = '0' (forward direction). 



As you can see in the waveforms, the rst signal is made high, The control word is loaded with the default value and the pattern “1100” is applied to the motors (motor_output1, motor_output2). There is no need for a control word to be loaded by the micro controller to load a control word and the motor controller can operate autonomously. Once the patterns are applied, the motor controller waits for the feed back form the motor (motor_feedback). 

Feedback from the motor
Upon receiving a feedback from the motor that movement by a step is complete, the next pattern is loaded into the motor_outputs wires depending on the direction of rotation. 


In the figure, you can see that upon receiving a feedback, the start shifting depending on the motor_direction. In this case, the motor_direction is '0' which is moving in the forward direction and hence the patterns are shifted right. As you can see, both the motor_outputs are shifted because the motor_select is “11” (both motors are selected). You can also see that upon receive of feedback from the motor, the step_counter decrements by 1. Shifting continues till the step counter becomes 0. The motor controller then starts the entire process again by loading the internal control registers with the value in the control_word_reg. Hence intervention by the micro controller is not necessary.

Loading a control word by the microcontroller

The control word to be loaded is put in the control_word input of the motor controller and the enable signal is made high. 
Control_word <= control word from MC
enable             <= '1' from the microcontroller

This loads the control registers with the values of the control word. As you can see in the waveform, the new control word (00110011) is loaded into the step_counter, motor_select and motor_direction. After enable goes low, execution of the new control word starts after receiving a feedback from the motor for the previous operation. 

In the waveform you can also see the step counter decreasing after each step. Since control_word(7) = '0', the motor controller is in the autonomous mode of operation. When the step counter expires, the control word is reloaded into the registers and the micro controller is not interrupted in the process. 
This control word moves both the motors forward by 3 steps autonomously. 

Finer control of motion
For finer control over the distance moved, the slave mode of operation is useful. The slave mode interrupts the micro controller after completion of each task. Consider rotating the motor right by 30 degrees. The method is rotate the left motor “forward” by “2 steps” while keeping the “right motor stationary”. (The resolution for a turn is 15 degrees per step). The “micro controller must be interrupted” after operation to load in the next word. The control word to be loaded is “10100010”. 

It can be seen in the waveform that after loading control word, motor_output1(left motor) shifts for 2 steps while the motor_output2(right motor) remains stationary. After 2 steps, the interrupt (task_completed) goes high and the motor controller waits for the next control word from the micro controller. When the micro controller loads in the next word, the motor controller resumes operation.

As you can see in the above waveform, the control word “10100010” interrupts the micro controller after completing its task through the task_completed signal. The micro controller acknowledges the interrupt, loads in a new control word “0011111”. This control word moves the robot forward without interrupting the micro controller. The robot moves forward until a new control word is loaded by the micro controller. 
Thus the operation of the motor controller is described in detail.
--
Abishek Ramdas
NYU Poly







Modification of OPEN8 core to interface with the Memory

The open8 core is to be modified to interface with the memory. The modification is described here.
REFERENCE TO THE OPEN8 INSTRUCTION SET GUIDE
Description : There is an implementation change to the open8 core so as to interface it with the memory provided with us. The implementation change is for instructions RTI (return from interrupt) and RTS(return from subroutine).

BUG
1. The interrupt occurs
2. There are 3 bytes that are stored in the stack The PSR and the 16 bit memory return address. They are stored in memory locations 127, 126, 125. This is with accordance with the Instruction set guide.
3. After stack operations is done, it  jumps to the ISR. ISR is pointed to location pointed to in memory by 129,128 as specified in the Assembly language reference manual.
4. In the ISR, it continues to execute code and when I use the RTI instruction, the control does not resume execution from where it left off. Instead it starts executing form location 0.
5. When RTI is executed, the stack operands are all popped out from the stack and available at the inputs but the controller does not read the data


MODIFICATION





You can see the interrupt signal going high when the CPU is executing at address 150 (decimal). The execution is completed and the next address 151(16 bits) is written into the stack along with the Program status register. Appropriately the stack pointer is loaded into the PC and corresponding write signals are generated to write the return address into the memory. The PC branches to ISR (indicated by address 771 in address line). The controller then starts executing code from that position till it encounters the RTI instruction (indicated by opcode 186 in the rd_data line). As you can see the stack is popped off to read the values.






But after the values are popped, the PC is supposed to load the return address (151 in our case) into the program counter but instead it loads 0 into the PC and starts executing from there.

This because of a delay the interrupt pipeline in reading the return data after it is popped.







It is to be seen in the waveform that when rd_data line has the return address (151 in our case) the cache_ctrl is idle. The cache_ctrl becomes cache_oper1 only after the next data from the stack is read (which is a 0 in our case). This causes the PC to be set to 0 (16 bits). This can be avoided by making the following changes in the code
  when RTS_C1 =>
        CPU_Next_State   <= RTS_C2;
        AS_Ctrl.Src      <= ADDR_SP;
        SP_Ctrl.Oper     <= SP_POP;

   when RTS_C2 =>
        CPU_Next_State   <= RTS_C3;
        AS_Ctrl.Src      <= ADDR_SP;
        -- Abishek start
        Cache_Ctrl       <= CACHE_OPER1; --line added
        -- Abishek end
        -- if this is an RTI, then we need to POP theflags                                                                                                
        if( SubOp = SOP_RTI )then
          SP_Ctrl.Oper   <= SP_POP;
        end if;

    when RTS_C3 =>
        CPU_Next_State   <= RTS_C4;
        -- Abishek start
        Cache_Ctrl       <= CACHE_OPER2;   --line added
        -- Cache_Ctrl     <= CACHE_OPER1; --original line
        -- Abishek end
        -- It doesn't really matter what is on the address bus for RTS, while
        -- it does for RTI, so we make this the default
        AS_Ctrl.Src          <= ADDR_SP;

    when RTS_C4 =>
        CPU_Next_State       <= RTS_C5;
        --Abishek start
        PC_Ctrl.Oper         <= PC_LOAD;   --these lines are added
        PC_Ctrl.Addr         <= Operand2 & Operand1;
        Cache_Ctrl           <= CACHE_OPER2;
        --Abishek end

    when RTS_C5 =>
        CPU_Next_State       <= PIPE_FILL_0;
        --Abishek start
        --PC_Ctrl.Oper         <= PC_LOAD; --these lines are commented
        --PC_Ctrl.Addr         <= Operand2 & Operand1;
        --Abishek end
        if( SubOp = SOP_RTI )then
          CPU_Next_State     <= RTI_C6;
          Cache_Ctrl         <= CACHE_OPER1;
        end if;

    when RTI_C6 =>
        CPU_Next_State       <= PIPE_FILL_1;
        PC_Ctrl.Oper         <= PC_INCR;
        ALU_Ctrl.Oper        <= ALU_RFLG;
        ALU_Ctrl.Data        <= Operand1;
        PC_Ctrl.Oper         <= PC_INCR;
        Int_RTI_D            <= '1';





After the modification, you can see that the RTI opcode (186) is executed, the return address (151) is read from the stack and loaded into the PC and the PC starts executing from 151 onwards.

INTERFACE BETWEEN Open8 and MEM

A 256 byte memory model is described in VHDL to using on chip BRAM for testing on FPGA board. It is interfaced with the Open8 soft processor. It is used as both program memory and data memory. The program can be loaded in binary into the memory, interfaced with open8 and can be simulated using modelsim.


1. Using the BRAM in the FPGA board as program memory/Data memory.

Memory Size
open8 has 16 bit address lines. I have implemented a 256 byte RAM (Uses the internal BRAM of the spartan3 FPGA) to connect it to the FPGA.

The memory entity is described below

-----------------------------------------------------------------------------
-- Memory: RAM
-- Desc: Instruction/ data memory
-- no of entries : 256 bytes
-- no of bits    : 8
-- we - write enable
-- re - read enable
-- en - select memory
-- addr - address(8 bits)
-- di - data in  (8 bits)
-- do - data out (8 bits)
------------------------------------------------------------------------------


entity RAM_NC is 
  port (
    clk  : in  std_logic;
    en   : in  std_logic;
    we   : in  std_logic;                     -- write enable provided en = 1
    re   : in  std_logic;                     -- enable signal for read
    addr : in  std_logic_vector(7 downto 0);  -- address 8 bits
    di   : in  std_logic_vector(7 downto 0);  -- data input 8 bits
    do   : out std_logic_vector(7 downto 0));
end RAM_NC;
This will serve as my program memory. The open8 processor starts executing from address 144 in the memory (PC=0000000010010000). So load program from that address.


The entity of the open8
component Open8_CPU
    port (
      Clock : in std_logic;
      Reset                    : in  std_logic;
      CPU_Halt                 : in  std_logic;
      Interrupts               : in  INTERRUPT_BUNDLE;
      --
      Address                  : out ADDRESS_TYPE;
      Rd_Data                  : in  DATA_TYPE;
      Rd_Enable                : out std_logic;
      Wr_Data                  : out DATA_TYPE;
      Wr_Enable                : out std_logic );
  end component;

Structurally connect the following lines
MEM CPU
addr <- Address(7 downto 0)
we   <- Wr_Enable
re    <-  Rd_Enable
do   <-  Rd_Data
di    <-  Wr_Data
en   <-  Address(15)

The open8 has an assembly code reference manual from where you can get the binary codes you need to load into the memory. I loaded a simple test program into the memory (location 144 onwards).


OPEN8 - MEMORY INTERFACE
FILES
1. Open8.vhd can be downloaded from www.opencores.org
2. Open8_pkg.vhd can be downloaded from www.opencores.org
3. RAM.vhd - Memory module
4. Open8_MEM.vhd - Interface between the memory and open8 processor (TOP LEVEL)
5. do_open8.do - do simulation file


Compile the VHDL files and run to do file to get the simulation
Note the instructions are read in the rd_data input and the value of the alu_regs changing according to the instruction under execution. 



Layer 0 - obstacle avoidance of SUBSUMPTION Architecture

PROJECT : It was required to build a system on chip using the following components
1.An open core from www.opencores.org
2.A custom block implementing a functionality
3.A memory which is generated by a memory generator built by professor Garrett Rose.

I read through different topics but my interest in robotics kicked in when I read a paper on subsumption architecture described in the paper “A Robust Control System for Mobile Robots” by the famous H.A. Brooks from the AI lab at MIT.

INTRODUCTION
Subsumption architecture is a layered architecture for building control systems for robots. The
 control system is composed of number of individual layers. Each layer performs a function independent
 of the other layers. For example consider a robot composed of the following layers

Layer 0: Obstacle avoidance
Layer 1: Wandering
Layer 2: moving towards an object of interest

Layer 0 is the lower most layer, There is a processor just for this layer that receives input from the sensors and avoids any obstacles. It performs only this job
Layer 1 is wandering where it moves in any direction, It communicates with the layer 0 in specifying
the direction. Layer 0 performs obstacle avoidance
Layer 2 is made of cameras etc that provide information on the object of interest. It detects the location
of the object of interest and generates a direction and commincates it to the wandering layer.

It seemed like a pretty good idea to implement a single layer on system on chip because of time considerations. Layer0 is obviously the layer to be implemented because
1.All other layers are built on top of this layer.
2.It requires a micro-controller which can be obtained from opencores.org.
3.It requires a data/instruction memory.
4.It requires a custom block for controlling the motor. 
5.Time is only a month.

Technology
Technical library: TSMC018.
Tools: Modelsim for function simulation;
           RTL compiler for synthesis;
           SOC encounter for automated design layout;
           Spectre for custom design simulation and power and timing analysis;
           Virtuoso for custom layout.

Components used
1. Open 8 uC
2. Custom memory (32Kbytes max) with following signals
1.Rd_en
2.Wr_en
3.Address lines
4.Data line (8 bits)
3. Custom Motor Controller block

REQUIREMENTS
1. Sensors to interrupt the uC when an obstacle is detected.
2. A uC to interact with the upper layers and control operation of layer 0.
3. A motor controller to interface with the motor.
4. An instruction and Data memory.

SPECIFICATION
1. Stepper motor.
2. Open 8 uC.
3. 32kBytes of memory can be interfaced (max).
4. Decoder to select between memory and motor controller.
5. Bus based architecture.
6. Sonar Sensors.

SYSTEM ARCHITECTURE

Reference : “A Robust Control System for Mobile Robots” by the famous H.A. Brooks
Actual interface with the sensors and motors is not done. The design is simulated, synthesized not actually implemented in hardware.