Intro to microcontrollers (long)

TK terryk at foothill.net
Thu May 27 01:05:09 GMT 1999


What I tell everyone is that the program is not really of importance. The
tables are the important part. Even the most rabid of us GM ECM hackers
don't change the program code, only the data tables. It's interesting to see
how GM goes about using the data in the program, but it's easy to get side
tracked on the program.

Data tables. Layout, inter-relationship, etc.

Terry Kelley

-----Original Message-----
From: steve ravet <Steve.Ravet at arm.com>
To: gmecm at efi332.eng.ohio-state.edu <gmecm at efi332.eng.ohio-state.edu>
Date: Wednesday, May 26, 1999 5:45 PM
Subject: Intro to microcontrollers (long)


>Shannen Durphey wrote:
>> Some guys seem to treat this programming info like it's reserved for a
>> chosen few.  Generally, the people on this list are willing to help, I
>> think they just forget where some of us stand in the puddle of
>> knowledge.
>> Shannen
>> *doing the clue mating dance*
>
>
>
>I'll start by saying I'm no expert on 6811 or GM stuff, so I'll try to
>keep it general.  Lets look at the 6811 architecture first.  It'll help
>if you have a Moto 6811 to refer to for this because it'll have diagrams
>of stuff that I can't duplicate in email.  The file I'm referring to was
>chosen basically at random from the moto site, right here:
>
>http://mot-sps.com/mcu/documentation/pdf/hc11rmr3.pdf
>
>There are probably lots of differences between this part and the one GM
>uses but it should be fine as far as the instruction set, core
>architecture, and other stuff I'll talk about.
>
>The "architecture" of a 6811 chip refers to the microcontroller core
>(MCU), and any peripheral devices connected to it.  Look at page 1-3 in
>the above manual for a diagram that shows the architecture of this
>particular chip.  Right in the middle is a box called "CPU".  This is
>called the core, and is the part that is common to all 6811 variants.
>The core executes instructions, contains the register file, and other
>parts that make the 6811 what it is.  Around the core you see other
>peripheral devices, like:
>  A/D -- converter (takes an analog voltage and coverts it to a number
>that can be used inside the processor)
>  SCI -- serial port for communications to other 6811s or a PC or
>anything else.
>  ROM -- Memory that can only be programmed once, retains data while
>power is off
>  EEPROM -- Memory that can be reprogrammed more than once, keeps data
>while power is off
>  RAM -- Can be reprogrammed, loses data when power is off.
>  Timer subsystem -- Generates pulses of specific lengths at specific
>times.  Can be used for injectors, ignition timing, lots of other
>things.
>
>etc.  There are dozens or more flavors of 6811, they all differ in the
>types of peripherals around the core but they all have the same core.
>GM 6811s also have external memory (the infamous PROM).  Picture that as
>another box in the diagram.
>
>So let's concentrate on the core.  Most microcontrollers/microprocessors
>share some common features.  One feature is called the register file.
>Registers are places inside the MCU where values can be stored
>temporarily while operating on them.  Look in the above manual at page
>1-4.  There's a list of registers inside the CPU.  The list shows these
>registers:
>A,B  (D)
>IX
>IY
>SP
>PC
>condition codes.
>
>First a note on bits.  The width of a register is expressed in bits.
>>From the diagram we see that A is 8 bits wide, B is 8 bits wide, IX, IY,
>SP, PC are all 16 bits wide.  The width of a register specifies the
>largest number that register can hold.  Each bit can be a one or zero.
>Counting in binary is like this:
>
>0000 0000 = 0
>0000 0001 = 1
>0000 0010 = 2
>0000 0011 = 3
>0000 0100 = 4
>0000 0101 = 5
>0000 0110 = 6
>0000 0111 = 7
>
>and so on.  an 8 bit register can hold values from 00000000 to 11111111
>which corresponds to 0-255.  A 16 bit register can hold values from 0 to
>65,535
>
>PC is an easy one.  It's the program counter, and it always contains the
>address of the next instruction to execute.  It always increases,
>meaning that the next instruction is always the one following the
>current one.  The only exception is a branch instruction which tells the
>processor to start executing from a different location.  It loads a new
>value into the PC.
>
>SP is the stack pointer.  There is usually a region of RAM set up that
>is called the stack.  The stack is used to store temporary values during
>a calculation, or to store values that are passed to a subroutine.  A
>subroutine is a well defined piece of code that takes some parameters,
>calculates a value based on them, and returns it.  An example would be a
>subroutine that calculates injector pulse width.  You would put it's
>parameters on the stack (temp, rpm, MAP, etc) and call the subroutine.
>The subroutine takes them off, calculates the pulse width, and puts it
>on the stack, then returns.  The calling routine takes the pulse width
>off the stack and sends it to the hardware.  It's called a stack because
>it's like a stack of plates.  You can only get to the top one.  To get
>to others requires removing the ones above it.
>
>There are instructions called "psh" and "pul" in the 6811.  These "push"
>values on the stack and "pull" them back off respectively.  The thing
>that makes it a stack is the fact that after you push a value on the
>stack the SP register is automatically decremented.  After you pull
>something off the stack it is incremented, so it always points to the
>"top" of the stack.  The stack starts at a high address and "grows"
>towards a lower address.  Might seem backwards but there are good
>reasons for doing it that way.
>
>IX and IY are index registers.  These registers are used to access
>memory (RAM,ROM,EEPROM, whatever).  Basically you put the address you
>want to read into IX or IY and then execute an instruction to read the
>value from that location into a register.
>
>A, B, and D are general purpose registers.  The above registers are
>special purpose.  General purpose registers are used to store the
>results from arithmetic instructions like add, subtract, shift, etc.
>>From the diagram you can see that A and B are 8 bits wide, hence can
>hold numbers up to 255.  If you need to work with larger numbers you can
>use the D register which is 16 bits wide.  The only thing is that D is
>really A and B stuck together.  If you store a value to D you wipe out
>what was in A and B.  A will be the upper 8 bits and B will be the
>lower.
>
>How does all this work together?  Lets say you want to calculate
>injector pulse width via something like this (simple example, not the
>way GM does it):
>
>pulsewidth=base_width + PE
>
>base_width has already been calculated from MAP and rpm or MAF or
>whatever.  You want to determine if the conditions for power enrich have
>been met, if they have then an additional amount of fuel is added.  In
>addition, if the conditions for deceleration are met you want to cut the
>fuel off altogether.
>
>Lets assume there's a PE table that gives additional pulse width, and
>it's indexed by RPM.  You only use the table if TPS is 80% or more.
>deceleration cutoff is determined by RPM being greater than 2000 and
>throttle at 0%.
>
>So the inputs to the calculation are TPS, RPM, base_width.  TPS and RPM
>come from sensors on the engine through the A/D and/or timer module.
>We'll assume that's already been done and the values are sitting in RAM
>somewhere.  TPS is an 8 bit value where 0=0% and 255=100%.  RPM is an 8
>bit value where 0=0rpm, 1=20 rpm, 2=40 rpm, 255=5100 rpm.  These values
>are stored in RAM, which starts at 0 and goes to 255.  Their particular
>locations are:
>
> 0x05 (TPS)
> 0x22 (RPM)
> 0x3f (base pulse width)
> 0x1f0 (PE table)
>
>The PE table is 16 bytes long and is located in ROM.  The first location
>represents rpm from 1000-1249, the second from 1250-1499, and the last
>from 4750 to 4999.  You index into the table based on rpm, and the value
>there is an additional injector pulse width that is added to the base
>width.
>
>So let's write some code.  semicolons indicate comments.  a $ indicates
>a hex value, no $ indicates decimal.  A # sign means the number is a
>constant, no # sign means indirection.  Indirection means the number is
>an address, and the value to use in the instruction is the value at the
>address:
>
> ldaa #0 ;loads the value 0 into register a
> ldaa 0 ;load the value stored at location 0 into a
>
>
>so here's the code:
>
>;first get the base pulsewidth, store it in register b
> ldx #$3f ;address of base pulsewidth
> ldab x ;load the base pulsewidth, store it into b
>
>;now check if PE mode applies
> ldx #$05 ;address of TPS
> ldaa x ;put TPS value into a
> cmp #204 ;compare a (TPS) to 204.  80% of 255=204
> bls decel ;if less than 80% skip PE lookup
> ;bls stands for branch if "less or same"
> ;it checks the result of the compare and
> ;takes the branch if the value of a was 204
> ;or less.  If it was greater than execution
> ;continues from this point.
>
>;PE mode
>;first read RPM and convert it to a value between
>;0-15 to index into the PE table
> pshb ;save value of b
> ldx #$22 ;address of RPM
> ldaa x ;get rpm value into b
> lsrb 4 ;divide rpm by 16 (convert to 0-15)
> ldx #$1f0 ;base of PE table
> abx ;ix=ix+b:  add rpm index to table address
> ldaa x ;get PE additional PW from PE table
> pulb ;restore original value of b (base PW)
> aba ;a=a+b add PE pulsewidth, result to a
>;
>; at this point register a holds the injector pulse width, either with
>; or without the PE addition.  Now check for decel and set PW to 0
>; if necessary
>; note that decel label is here.  If the PE calculation wasn't
>; necessary then the program jumped straight here, otherwise
>; it executed to here
>;
>;for decel:  if TPS=0% and RPM > 2000 than set the injector PW to 0
>decel:
> psha ;push PW onto stack
> pulb ;pop PW into reg b
> ldx #$5 ;address of TPS value
> ldaa x ;get TPS into a
> cmp #0 ;is it zero?
> bne done ;if not zero, not in decel mode, done
> ldx #$22 ;address of RPM
> ldaa x ;get rpm to a
> cmp #100 ;100=2000 rpm
> bhi done ;if >2000, not in decel mode, done
>
>;if we execute to this point them RPM is < 2000 and TPS is = 0.
>;that means decel mode, so set the base PW to 0
> ldab #0 ;PW=0
>done:
> yada yada yada
>
>More code comes here to actually turn the injector on for the time
>specified by the PW.
>
>Some of the above might need a little more explanation.  Whenever you
>see two instructions like this:
> cmp #204 ;compare a (TPS) to 204.  80% of 255=204
> bls decel ;if less than 80% skip PE lookup
>you are implementing a test.  The compare instruction compares register
>a to the value 204.  It sets some bits in the condition code register
>depending on if the values are the same, greater, less, etc.  The bls
>instruction checks those bits and takes the branch if it determines that
>the values was "less or same".  There are lots of branches, for equal,
>not equal, signed/unsigned greater/lessthan, etc.
>Most arithmetic instructions set condition codes so you might see code
>like this without the compare:
> aba
> beq label
>In this case if the sum of a and b was zero then the branch would be
>taken, otherwise execution falls through to the next instruction.
>
>
>A few last notes.  labels are used to avoid repeating the addresses of
>the variables all the time (#$5, #$22, etc.).
>
>This is the first 6811 program I've ever written and I'm sure that are
>both syntax errors that would keep it from assembling, and I'm sure that
>the code could be condensed.  But it illustrates how you'd write some
>assembly code to get what you want done.
>
>I haven't addressed how to set up all the peripherals, how to use the
>A/D converter, etc. but those are a little more advanced than this
>example.  Once you understand how assembly language works you can look
>at the examples in the manual to find out how to use the peripheral
>devices.
>
>Also, it's a much simpler problem to write the assembly to do what you
>want than it is to stare at a disassembly (without comments!) and figure
>out what it does.  But if it wasn't hard it wouldn't be as much fun.
>
>Hope this helps some people out, post any questions but please snip out
>irrelevant parts.
>
>--steve
>
>
>
>
>
>
>--
>Steve Ravet
>steve.ravet at arm.com
>Advanced Risc Machines, Inc.
>www.arm.com
>




More information about the Gmecm mailing list