RS-232 Communication with MS2/Extra

Only for use with the MS2 Extra code

By Philip Ringwood (daxtojeiro), James Murrey (jsmcortina) and Ken Calver (muythaibxr)

Updates and errors? please PM Werner (woh)

Please Note:

All of these instructions / diagrams are to be used at your own risk, like most things there is more than one way to do the same thing. We have tried to offer a method that we have tested or that others have tested for us. No warranty expressed or implied.

Use at your own risk.


July 7, 2008. updated to rel. 2.0.1 MS2/Extra


MegaSquirt 2 Extra (MS2/Extra) comes with an RS-232 port that allows loading new firmware and the operation of such applications as MegaTune. With a program such as Hyperterminal you can send some rudimentary commands to MS2/Extra. With a programming language such as C or Visual Basic you can do more sophisticated communication to retrieve data from MS2 or modify the tables. The only requirement is that you can write a program to send and receive strings and data (an array of bytes) with RS232 (also referred to as COM1, COM2 etc)

In this section I'll explain some of the commands for MS2/Extra and demonstrate how to use Visual Basic 6.0 to use these commands. I'll also show you how to read the megaquirt-ii.ini file to get more information on how to use the data from MS2/Extra. You can read the megaquirt-ii.ini file with Word or an editor like Vim . You can not read the file using Notepad. To load the file in Word use the File>Open menu and then in the View menu select web view.

A VB 6.0 example program is available for download. It shows how to download real time variables, and tables.


Commands for MS2/Extra RS-232

The commands for sending and receiving data to and from MS2/Extra via RS232 use a single character and in some cases the character is followed by one or more bytes of instruction or data. In the case of primary commands compatible with the CAN interface, the first byte is the ANSI code for a Command Character, the second byte is the CANid or I/O identification and is always 0 (zero) for MS2/Extra, the third byte specifies the Table Index (tble_idx). These three bytes may be followed by additional data or instruction bytes. For some commands a Word (16 bits) is required. A Word variable will be represented here with two bytes (8 bits each). The the high byte will have an 'H' as the suffix, and the low byte an 'L' suffix. The brackets <var> indicate a one byte variable except for a data array. The parenthesis on the next line after the command character, for example "a" is (61 ), indicate the ANSI code for the command character. It is the ANSI code that is send as a byte to represent the character. Examples with single quotes are bytes seperated by a space.

Primary Command Characters

Three byte commands:

"a", 0,<tble_idx>
     (97) - MS2 returns an array from the outpc array in MS II
"r", 0,<tble_idx><offset_H><offset_L><numb_points_H><numb_points_L>
     (114) - Read data from MS2. Generic form of the 'a' command that controls the size and start of the array returned
"w",0,<tble_idx><offset_H>,<offset_L>,<numb_points_H><numb_points_L> <data array >
     (119) - Write data to MS2. The reverse of the 'r' command - sends data to MS II.
"e", 0,<tble_idx>,<offset_H><offset_L><numb_points_H><numb_points_L> <data array >
     (101) - Write with echo. Returns the data written. Same as "w" but with echo for verification.
"y", 0, <tble_idx>
     (121) - Verify that input data in a ram block matches the corresponding flash block.
"b", 0, <tble_idx>
    (98) - Burn the ram copy of tbl_idx into the flash memory.
"t", 0, <tble_idx><data array >
     (116) - re-flashing new Coolant, MAT, Ego, and MAF tables. tble_idx = 0 - 3

You must add a delay of >200ms after the <tble_idx> whenever changing the page. The first time a new <tble_idx> is used/changed a delay is required after the <tble_idx> before sending any further information. Failure to do so will result in the return of no data.

Single Character Commands

    (65) - MS2 sends the real time variables as an array of 152 bytes (will continues to change).
    (99) - Test communications - MS2 sends high byte of variable 'seconds'
    (83) - Signature - MS2 sends an identifier 32 character string (this is not the version)
    (81) - Revision - MS2 sends the code version as a 20 character string

" ! " Commands

The "!" commands are multiple character commands to initialize, reboot, and load new firmware. They all start with '!' .

"! x"  
     '33 120'  - causes MS2/Extra to re-initialize various program values,
"! ! x"
     '33 33 120' - reboot MS2/Extra and start running.
"! ! !"
     '33 33 33' - reboot MS2/Extra and come up ready to load a new code version

CANid - an integer byte from 0-15. Use 0 for MS II, for other (GPIO) devices it is arbitrary depending on how a user has configured the devices in his network. Set to 0 for communications between PC and MS2/Extra.

tble_idx - a byte from 0-15 that specifies the block of data from which to get/send data. The variable blocks in MS2 corresponding to tble_idx  0-10 are as follows:

These are in flash only and are downloaded with the 't' command. 1024 signed 16 bit words;
0 - array of coolant temperatures vs ADC counts,
     units are deg multiplied by 10, so 1801 represents 180.1 degrees.     
1 - Same as coolant temp table above except array of manifold air temperatures.
2 - array of ego reading vs ADC counts , 147 = 14.7 afr
3 - array of maf reading vs ADC counts , mg/sec x 10.

These contain the user tables and other constants
Also see MT megaquirt-ii.ini file for offset address and size
4 - page 1, first input ram structure ( AFR table)
5 - page 2, second input ram structure
6 - output ram structure ( real time variables, use "A" cmd)
7 - page 3, Ignition Table 1 & 2
8 - page 4, Ignition Table 3
9 - page 5, VE table 1, 2 & 3
10 - page 6 (not used at time of this writing)


Simple communications with VB 6.0

Microsoft VB 6.0 (and Microsoft Excel) have the capability to easily communicate with RS232 using the Microsoft COMM object. To use the Microsoft COMM object it must be setup to the same communication properties as MS2. First open VB using a form and then place the MS COMM object on the form. It will be named MSCOMM1. Place a command button on the form and copy or type in this code.

Private Sub Command1_click ()
    ' Buffer to hold input string
   Dim Version As Variant
    ' Use COM1.
   MSComm1.CommPort = 1
   ' 115200 baud, no parity, 8 data, and 1 stop bit.
   MSComm1.Settings = "115200,N,8,1"
   ' Tell the control to read entire buffer
   ' when Input is used.
   MSComm1.InputLen = 0

   ' Tell the control to get input as string
   MSComm1.InputMode = comInputModeText
   ' Open the port.
   MSComm1.PortOpen = True
   ' Send the get version command to MS
   MSComm1.Output = "Q"
   ' Wait for data to come back to the serial port.
   Loop Until MSComm1.InBufferCount > 10

   ' Read the response in the serial port.
   Version = MSComm1.Input   
   ' Close the serial port.
   MSComm1.PortOpen = False
End Sub

With RS232 connected to the correct port and MS2 powered up you will receive the version string from MS2 when clicking the command button. Download VB 6.0 example that demonstrates many of the above commands as well as reconstructing tables.


"a" Command

"a", 0,<tble_idx> (not recommended)
' 97 0 6' - example, sending this will return buffered real time data of 113 bytes..
MS2 returns a byte array from the txbuf which is a copy of the outpc array. For this command the data is buffered as it is sent so that the data is not changed during the send operation and all bytes are from the same instant of time. For real time data this assures the different variables correctly relate to each other.

Use the "A" command for reading real time variables.

Use "r" for fixed data to avoid the extra time of buffering the data.

"b" Command

"b", 0, <tble_idx>
'98 0 5' - example to burn table 5 to flash
Used to tell MS II to burn the ram copy of tble_idx into the Flash memory. The command is only for ram buffered data because on tuning it has to be fast. There is a timeout of ~2ms for flash to be erased and interrupts disabled.

"e" Command

"e", 0,<tble_idx><offset_H><offset_L><numb_points_H><numb_points_L> <data array>
'101 0 5 0 0 144', <data array> - example send 144bytes to MS2 and have MS2 echo them back
The 'e' (echo) command is the same as 'w', except that after MS2 has received all the bytes from the sender, it echoes them back for verification. Thus a sender who has sent n bytes to be written should expect n bytes back from MS II starting after he has sent the last byte to be written.

"r" Command

"r", 0, <tble_idx><offset_H>,<offset_L>,<numb_points_H><numb_points_L>
'114 0 5 0 0 144'- example, MS2 will reply with 144 bytes of the VE table 1
Generic form of the 'a' command. The returned bytes from MS II are not buffered. Send 'r', 0, <tble_idx>. followed by 2 bytes specifying the offset from the array or structure corresponding to tble_idx, followed by 2 bytes specifying the total number of data bytes to return. After all 7 bytes are received, MS II will start sending the requested number of bytes.

In order to fetch the 256 byte VE table, we would need to send the following out the serial port:

114 (byte value for lower case 'r')
0 (one byte for CANid, always zero for RS232)
9 (one byte for tble_idx)

delay of >200 ms (if table index changes)

0 (High byte of location index)
0 (Low byte of location index)
1 (High byte of the number of data points)
0 (low byte of the number of data points)

The table definition and variables are contained in the megasquirt-ii.ini file. Some commonly used tables are repeated here for convenience

AFR target, VE fuel, Ignition Advance

For scaling and more details, see the megasquirt-ii.ini file. Pages are somewhat different than variables outlined above in the "A" command, but the concept is the same. Here is a line with headings from the target AFR table 1 (afrTable1) on Page = 1:

Variable               index                 <------- scaling ------>
name       type, size, offset, shape, units, scale.  translate  lo,  hi, digits

afrTable1= array, U08,  48,  [12x12], "AFR", 0.10000, 0.00000, 9.00, 20.00, 1

The type is either array, bits, or scalar where an array is multiple bytes of data (e.g. tables) bits is a byte where each bit may have a True/False meaning, and scalar is a single number.

The size indicates the memory size. U08 is an unsigned 8 bit number, U16 is an unsigned 16 bit number and will require two bytes of data.

Shape tells you the number of dimensions to the array. A [12x12] shape indicates a two dimensional array such as a VE table. A [12] is a one dimensional array such as the x or y axis table data for MAP and rpm. The tables start on the lower left going from left to right and up. See the example VB program for creating a table.

Units are the human readable units. ADC means the value from the analog to digital converter before they are scaled. ADC units typically represent 0-5V max using 0-255

The scaling is done with a multiplier (scale) and an offset (translate) to get to user units (in the above example AFR) use this formula:
userValue = (msValue + translate) * scale.

The lo and hi value indicate the range of the values. In this example for an input of 0-5V (Innovate 0-5V LC-1) the user units will range from an AFR of 10 to 20. The scaling values will be different for different sensor settings.

The digits indicates the number of useful digits after the decimal point.

Do a search of the variable in the megasquirt-ii.ini file for details.

VB example

This snippet of code demonstrates how to read the VE table1 and constants from page 5 (tbl_idx=9) into an array. This is only the table and does not include the axis definition.

Dim DataOut As Variant
Dim byteArray(6) As Byte

' Send commands as array of bytes
MSComm1.InputMode = comInputModeBinary

ReDim byteArray(2)
' Select a page
byteArray(0) = Asc("r")
byteArray(1) = 0
byteArray(2) = 9
MSComm1.Output = byteArray

delay 200

' Sent starting address (0)
ReDim byteArray(3)
byteArray(0) = 0
byteArray(1) = 0

' Send size (256 bytes)
byteArray(2) = 1
byteArray(3) = 0

' Send the commands to get a page and return the variables
MSComm1.Output = byteArray

' wait 200msec
delay 200

' grab data from comm port.
DataIn = MSComm1.Input

"t" Command

"t", 0, <tble_idx> <data array>
'116 0 3' delay 50ms <table data> Example for re-flashing
For changing calibration data in MS2. Use for re-flashing new coolant, MAT, Ego, and MAF tables. These tables are all 1024 word (2 bytes) tables. The 't' command is followed by <tble_idx> of  0-3, to identify the table of interest. At that point the MS II erases the table flash sector entirely (that is why you do NOT want to be driving while this is going on). So you want to delay about 50 ms before sending the the rest of the data, which consists of the table words. These are sent in order of ascending index, msb byte first, then lsb byte for each of the 1024 16-bit words.

"w" Command

"w",0,<tble_idx><offset_H>,<offset_L>,<numb_points_H><numb_points_L> <data array >
'119 0 4 0 20 0 2 0 250' example of sending cranking rpm of 250
The 'w' command is the reverse of the 'r' command - it writes to MS2. The format of the command is identical to 'r', except send 'w' and follow the seventh byte with the nbytes of data to be written to MS II ram.

There will, of course, be timing issues for writing some tables, as you are writing to flash instead of RAM, and the serial line may be quite a bit faster than the device, hence buffer overflow will occur.

  Back to Commands


"y" Command

"y", 0, <tble_idx>  
'121 0 5'
Used to verify that input data in a ram block matches the corresponding flash block. This is typically used after a flash burn command to verify the data were correctly burned. MS II sends back a 2 byte word, lsb first, that holds the number of times a ram and flash byte pair failed to match. So if it returns a zero, all is good.

"A" command

"A" (65) - MS2 returns an array of bytes from the outpc array in MS2. For this command the data is buffered as it is sent so it is not changed between bytes during the time of transmission. use this command to retrieve real time variables from MS2.

The "A" command will return the real time variables as an array of 152 bytes ( this may change with future revisions). Each byte or multiple bytes represents a variable in MS2. The variable names and properties for each byte are described in the msn-extra.ini file shipped with each version of MS2/Extra. This table is a summary of the MS2/Extra variable description.

The data returned is 'raw' data as stored in MS2/Extra. To obtain maximum resolution and at the same time use as little as possible memory space the variables are scaled to best fit into the available memory. This means that some variables will not be recognizable until they are scaled to some user readable form. The scaling is documented in the file megaquirt-ii.ini file and the table.

As an example lets assume we have send the string "A" and received an array. We want to know the Air Fuel Ratio. To get the scaling we have to use the file megaquirt-ii.ini  Open megaquirt-ii.ini (found along with the firmware) and search for afr1 after the line [BurstMode]

afr1 = scalar, S16, 28, "AFR", 0.100, 0.0

The AFR value is a signed 16 bit variable made up of the 28th and 29th byte of the returned array. To calculate the AFR use the last two fields AFR = (afr1 +0.0) * 0.1 or stated differently; the AFR stored in MS2/Extra is ten times the actual AFR. This data is also recorded in this table.

VB 6.0 example:

   Dim Data As Variant

   ' Send command to MS as text
   MSComm1.InputMode = comInputModeBinary
   ' Send the commands to get a page
   MSComm1.Output = "A"

   ' wait 200 ms    delay 200
   Data = MSComm1.Input ' grab data from comm port.

Back to Commands


"c" command

Returns the high byte of the variable seconds. Used to confirm RS232 connection. Read the value like this in VB

Dim DataIn As Variant
With MSComm1
    .InputMode = comInputModeBinary
    .Output = "c"
    DataIn = .Input
End With


"Q" & "S" command

The 'Q' and 'S' commands (both caps) are used to retrieve two indicators of the MS II code version. "Q" is the 20-byte ascii string for the revision number of the code version. The revision is changed in the code whenever there has been an input parameter or output variable added. "S" is for a 32-byte Signature string. The Signature string is changed in the code whenever a new feature is added . Read version as shown above in VB

" ! " Commands

Re-initialization, reboot and code reloading commands, all start with '!'. The complete commands are:

"!x" causes MS II to re-initialize various program values, for example the ncylinder-dependent coefficient for computing RPM, to be re-calculated. It should be used only when the following specific variables are changed:

"!!x"   If rpm < crank_rpm, this causes the program to reboot itself and start running.

"!!!"  If rpm < crank_rpm, this is the same as reboot, except the program comes up ready to load a new code version.

Back to Commands