This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MPS430 op-codes, documentation, and other questions

Other Parts Discussed in Thread: MSP430G2231

I'm getting started with the MPS430 processor via the LaunchPad kit and have a number of basic questions.  I do not have much microcontroller experience although I'm a software developer and did some 8088 programming decades ago.  If there is a more appropriate forum than this please direct me.

To help me get familiar with the processor, I'm trying to "hand assemble" simple code snippets into machine code.  But the documentation is driving me batty.  I'm mainly looking at the "MSP430x2xx Family Guide" documentation.

Here are some starting questions if anyone can help answer:

1.  Why is it named "MSP430x2xx" -- how do we know what processors that refers to?  There is no list in the guide itself.  The LaunchPad comes with the MSP430G2231 processor for example.  Wouldn't that be a "MSP430x2xxx" classification?  Or is the G dropped? How does that classification work?

2. How do you find the actual instruction op codes in the "MSP430x2xx Family Guide" documentation?  There is a section: "3.4.5 Instruction Set Description" with figure 3-20 called the "Core Instruction Map".  This is the closest thing I can find that might indicate the op codes, but I'll be darned if I can figure it out.  For example, for the "jump" instructions, there are a bunch of values such as 20xx, 24xx, 28xx, etc.  I can't understand how to relate these values to the instruction fields depicted in section "3.4.3 Jumps" which shows a 3 bit op-code field, then a mysterious 3-bit field called "C", followed by the 10-bit PC Offset.

Comment:  I have deduced that the manual is organized to make it easy to update and modify for different processors, by "factoring out" redundant information.  However, this makes the manual really hard to use.  It would be helpful for example if each instruction listed its op code in the main instruction reference, or if there were at least a simple list of op codes corresponding to the instructions.

3.  Symbolic Mode addressing.

The manual makes it difficult to distinguish "Assembly Code" from "(pseudo) machine code" in section 3.3.  For each mode, it shows an example of "Assembler Code" and something called "Content of ROM" which seems to be a translation into pseudo machine code, or perhaps better termed "core instruction format".  I'm deducing that "Symbolic Mode" addressing is not an actual CPU concept but more an Assembler concept.  It does seem to use a special case of "Indexed Mode" or even "Indirect Autoincrement Mode" where the PC is the indexing register.  From a CPU concept standpoint, the word "Symbolic" has no meaning.

But the documentation for this mode is not clear.  It describes the source address as (contents of PC + X) and the destination address as (contents of PC + Y), but the example seems to indicate the source address as (contents of PC + 1 + X) and the destination address as (contents of PC + 2 + Y).  In other words, the words following the PC counter address are added to their own address, not the PC counter.

Those are some starting questions which I would appreciate some insight into.

-SB

  • My understanding of the “Jumps instruction” for MSP430 is as follows.

    Bit-15, 14, 13 are the “op-code”.

        For all “Jumps instruction”, they must be 0, 0, 1.

    Bit-12, 11, 10 are the “C” (or condition) of the Jump.

       For JZ, they are 0, 0, 0.

       For JNZ, they are 0, 0, 1.

       For JC, they are 0, 1, 0.

       For JNC, they are 0, 1, 1.

       For JN, they are 1, 0, 0.

       For JGE, they are 1, 0, 1.

       For JL, they are 1, 1, 0.

       For JMP, they are 1, 1, 1.

    Bit-9, 8, ..., 0 are the 10-bit PC offset (actually, offset/2).

  • My understanding of the address mode for MSP430 is as follows.

    For the Destination Address of a Double-Operand, there are only two address modes, namely (a) Register-mode and (b) Indexed-mode.

    For the Source Address of a Double-operand, or the Address of a Single-operand, there are two additional address modes, namely (c) Indirect-mode and (d) Indirect-auto-increment-mode.

    But when the register is R0/PC, R1/SP, R2/SR/CG1, or R3/CG2, the address modes behave differently (the “orthogonal architectural” is gone with the wind).

    Specifically, R0/PC in Indirect-auto-increment mode is called (e) Immediate-mode.
    R0/PC in Indexed-mode is called (f) Symbolic-mode.
    R2/SR in Indexed-mode is called (g) Absolute-mode.

    “When I use a word,” Humpty Dumpty said, in a rather a scornful tone, “it means just what I choose it to mean—neither more nor less.” -- Lewis Carroll's Through the Looking-Glass

  • Thanks, those answers help clarify.

    To follow up:  did either of you figure this out from the "MPS430 Family" document, or is there a better document that describes the processor instruction set and addressing modes?

    Since posting, I found that Wikipedia seems to have a clearer explanation of the instruction set and opcodes.  But I'd much prefer to find good, clear, accurate TI documents to work from if they exist.

    I'm still not clear on "Symbolic Mode" and what address the offset is added to.

    Regards,

     

    -SB

  • s b said:
    ... But I'd much prefer to find good, clear, accurate TI documents to work from if they exist. . . .

    I prefer that too, but no luck so far.

    s b said:
    ...I'm still not clear on "Symbolic Mode" and what address the offset is added to.

    The Assembler&Linker will calculate the PC offset of the Symbol and put that offset into the Object Code. When that Object Code is executed, the CPU will use PC in Indexed-mode with that offset (undoing what Assembler&Linker did).

    For example: Assume that the RAM at 0234 has a Symbolic name "bar", and you want to zero it. Using Symbolic-mode, you write "mov.b #0,bar". The Assembler&Linker generates an instruction at F800-F803: 43C0 0A32 (where 0A32=0234-F802 is the PC offset of 0234). During execution, the effective address of the destination is F802+0A32=0234 (which has the Symbolic name "bar").

     

     

     

  • s b said:
    Why is it named "MSP430x2xx"

    The MSPs come in several main families, indicated by the first digit. 1 is the oldest, 3 is discontinued, 2, 4 and 5/6 are the newer ones.

    All families share certain characteristica. So do have all 1x devices a basic clock module, all 2x have a basic clock module +, the 4x have a FLL+ clock module and the 5x/6x devices an universal clock system.

    The different user guides describe the common characteristica of all devices in one family, as well as all hardware that is available in one (but not all) devices of a family.

    E.g. each 3x member may have one or more USI or USCI modules (or none at all), but the 2x family USCI module differs from teh 5x/6x family USCI module. (and the 1x family has USART modules).

    Which specific hardwar eof this collection is available for a particular family member is written into the device datasheet. These datasheets may be for a sub-group of MSPs which are mostly identical in terms of operation conditions and other specs, but may have a different number of pins and therefore ports and/or ADC inputs, or different amount of ram or flash. E.g. the 5438 and the 546 ar eidenical except for 64k of additional flash in teh 38 which is not in the 36..
    The 5437 and 38, however, have the same amount of flash, but the 37 has only 2 instead of 4 USCI modules and 80 instead of 100 pins. The 35 then is like the 37 but again with 64k less flash. All of them share the same datasheet.
    The 54xxA, however, ar eof th esame family, but have different specs (higher operating frequency, additional REF module and different settings for the voltage supervisor etc.), so they have their own datasheet, but share the same users guide, since the modules are the same and so are the register descriptions etc.

    One could melt all this into individual datasheets for each and every MSP, but this would result in a hughe bunch of large datasheets, adn while it would make it easier to work on one device, it would also make it way more difficult to move between devices.
    And the effort for keeping them all up-to-date would be enormous, including the increased chance for errors.

    Well, an MSP is no TTL device.

    s b said:
    How do you find the actual instruction op codes

    The MSP core is orthogonal. So there are no tmany individual opcodes, bu trather each opcode (except for a few unique instrucitons) is assembled by a set of parameters.

    OCY has explained the jumps. The arithmetical instructions are assembled by

    • operation (AND, OR etc.)
    • source addressing mode (register, indirect etc.)
    • source register (for register or indirect mdoes)
    • destination address mode
    • destination register
    • byte/word mode flag

    See fig. 5-22 for those double-operand instructions (5x users guide, 4.5.1.1 in 2x users guide)
    The operation is determined by the upper 4 bits (12 of the 16 combinations)

    The jumps are in the 2000-3f00 range and include the 10 bit signed offset in words, as well as the condition (compared against the status register)

    Single-operand instructions such as RRC or push do not have source register and addressing mode, so there are 5 more bits for the instruction

    And then there are a few special operations which don't fit into any scheme, such as RET and RETI.

    The new MSP430X instrucitons (with 20 bit operands)fille hte previously unused ares on 0xxx and 1400-17ff (address mode operations, which work only register/register except for the MOVA) and the also unused gap in 1800-1fff is filled by the extension word that precedes any 430X instruction and contains the mising 4 bits for the 20 bit source and destination operands.

    s b said:
    It would be helpful for example if each instruction listed its op code in the main instruction reference, or if there were at least a simple list of op codes corresponding to the instructions.

    But there is :) the 'OP-Code' of a MOV instruction is 0x4xxx. The 12 unspecified bits depends on source an ddestination register and addressing mode. There's no point in listing all possible variations.

    s b said:
    For each mode, it shows an example of "Assembler Code" and something called "Content of ROM"

    I think, here the users guide is overly detailed. However, I also had some problems to understand the difference between absolute and symbolic mode at first.
    You're right, it is more an assembler concept than a hardware mode. In fact, indexed, absolute and symbolic mode use the same addressign mode: register indexed. While indexed mode uses any registerexcept R2 and R3, absolute mode uses R2, which then acts as constant generator, returning 0 as offset value. And symbolic mode uses the PC as index register. So on execution level, all three are the same. They are, however, used in a completely different way.
    Indexed mode is usually generated with a base address as constant part and the index in a register. Which is determined at runtime. There are, however, cases where the index is the constant part (e.g. when addressing an element of an array, wehn the array pointe rwas passed to the function and is dynamic). THen the register is the base and the constant part the index.
    Absolute mode can be seen either way, either an index to the constant base 0 or nan index 0 to the constant offset X.
    The last, symbolic mode, is calculated at linktime relative to the PC. It makes not much sense at first, but if you have code that uses local static constants (such as format strings for printf), these constants will be stored right before or after the code. So their offset to the PC is always the same, independent of the absolute code position.
    This way, you can jsu tload the code from any location (e.g. external storage) to RAM and execute it there.

    s b said:
    But the documentation for this mode is not clear.  It describes the source address as (contents of PC + X) and the destination address as (contents of PC + Y), but the example seems to indicate the source address as (contents of PC + 1 + X) and the destination address as (contents of PC + 2 + Y).

    Ahm, no. Or yes, depends on the point of view.
    To load the offset part of the symbolic mode, PC is incremented (by 2, as PC always has an even value) for the source and then again for the destination operand. This happens in the normal process of fetching the opwerands. So it is actually PC+x and PC+y, but PC at the moment PC+y is calculated isn't the same PC as it was when the opcode was fetched. And isn't the same as it will be when PC+Y is calculated.

    However, if you don't plan to write an assembler on your own, just use the mnemonics and all is done for you.

    It's all in the faily users guides.

    However, it sometime shelps to look into the other families users guides (there aren't that many, only 1x, 2x, 4x and 5x/6x)
    Sometimes, the newer ones have a more detailed or straightened descriptions which did not make it (yet) into the 'older' family user guides.

    Did you ever try to write a documentation? It's not an easy task, and the most hated one for most engineers. (and those who do not hate it or are explicitely hired to do it, are usually no engineers, so there's an informational gap)

  • Thanks for the good explanations.  I am looking at this as an assembler writer to try to really understand how the machine instructions work.

    I agree, it's darn hard to write good documentation, especially for something as complex as these processors.  IBM did quite a good job for the original IBM PC.  The MSP430 docs are a good start but seem leave out critical info, perhaps assumed to be common knowledge to microcontroller experts.  (I have written a ton of documentation and  work at addressing my own complaints, and it isn't easy.  I believe documents really have to be "alive" and incrementally improved based on user feedback).

    For example, it should be explicitly documented how and when the PC is incremented during instruction processing, using an algorithm.  You explained it, but without that knowledge, (PC + X) is ambiguous.

    To summarize using Symbolic Mode as an example, it seems then that at the beginning of instruction execution, the PC points to the instruction word.  If an additional extension word is needed for a src operand, the PC is automatically incremented to fetch that word.  If the addressing mode involves the PC, such as "Symbolic" mode, then the current PC value is added to the extension word contents to get the address of the operand.  If an additional extension word is needed for the dest operand, the PC is incremented again to fetch the next extension word.  If it is also "Symbolic" mode, the current PC value is added to the extension word contends to get the address of the dest operand.  After the instruction operation is performed (or is it before???), the PC is incremented again automatically to fetch the next instruction, unless the last instruction was a branch instruction of some sort.

    I'm still a little confused about the nomenclature "@PC+" as used to describe the "Immediate Addressing Mode".  "@Rn+" seems clear to me -- use the contents of Rn as an operand address, then increment the register contents.  The problem I have with "@PC+" is that the PC is automatically incremented as part of fetching an extension word, so does the "+" cause an additional increment???

    It would be helpful for example if each instruction listed its op code in the main instruction reference, or if there were at least a simple list of op codes corresponding to the instructions.

    But there is :) the 'OP-Code' of a MOV instruction is 0x4xxx. The 12 unspecified bits depends on source an ddestination register and addressing mode. There's no point in listing all possible variations.[/quote]

    What throws me off with the "Figure 3-20 Core Instruction Map" in section 3.4.5 is that the jump instructions have codes like 20xx, 24xx, etc.  This implies 8-bit opcodes, but the jump instruction layout in Figure 3-11, section 3.4.3 shows a 3-bit opcode and a 3 bit "C" field.  From Wikipedia I see that the "C" field (unexplained in the TI Doc) is a "condition" field and is really part of the op-code, so we have a 6-bit opcode, which still doesn't correspond to the 8-bit opcodes implied by "Core Instruction Map".   It's little peculiarities like that which make the documentation an exhausting puzzle to be solved rather than an efficient, enabling tool for productive work.

    I appreciate all the input and maybe can use a PDF editing tool to augment the TI doc with expanded explanations for my use.

    Regards,

    -SB

  • s b said:
    If it is also "Symbolic" mode, the current PC value is added to the extension word contends to get the address of the dest operand.

    The PC is just another register like all others. you can add to it, set ot clear individual bits, use it as index for any memory access. Fetching an instruction or an operand is jsut a normal indexed address bus access.
    There are some (few) special handlings: if the PC is the destination of any operation, then the next instruction fetch is delayed by one cycle (and then takes place with the new PC value instead of the incremented old one). Also, its LSB is always zero (or at least, it isn't put to the address bus)
    However, the microcode will always use the @PC+ for any code or operand fetch. Why implement additional forms of access, when the circuitry is already there. I think, the documentation just doesn't explain this in detail. It doesn't explain the interleave of instruciton execution and next isntruction fetch too. It is not mentioned anywhere, just the cycle counts tell about it. And soem of the errata entries, such as the fact that you cannot place a breakpoint directly behind an instruciton entering LPM (or it will trigger before LPM is enterd) or that even after clearign GIE, an interrupt may occur after the next instruction.

    s b said:
    is that the PC is automatically incremented as part of fetching an extension word, so does the "+" cause an additional increment???

    i think it's rather an inconsistency in teh documentation. The externsion word stuff is MSP430X/X2 while mos tof the documentation was written for the original MSP430 (non-X) instruction set.

    s b said:
    What throws me off with the "Figure 3-20 Core Instruction Map" in section 3.4.5 is that the jump instructions have codes like 20xx, 24xx, etc.


    See at it as

    001000xxxxxxxxxx to 001111xxxxxxxxxx

    or more precisely:

    001 yyy xxxxxxxxxx where 001 is the 'jump opcode' and 'yyy' is the condition and 'x' the signed offset in words.

    You never worked with a spark? There the MSB determines whether it is a call instruction (with 31 bit address in words)  or anything else.

    s b said:
    so we have a 6-bit opcode, which still doesn't correspond to the 8-bit opcodes implied by "Core Instruction Map"

    the notation with hex digits dosen't allow the listing of insignificant half-nibbles. And a complete 256x256 table wouldn't help anyone :)

    However, the assembler and linker know how to build the opcodes from the mnemonics. So unless you want to write one of them (or debug them)...

  • Thanks for those explanations that dig under the surface, it's getting clearer.

    However, the microcode will always use the @PC+ for any code or operand fetch

    I'm still not clear on the nomenclature "@PC+".  What exactly does it mean?  If you are hand-assembling machine code (or writing an assembler), it seems you need to know the details of the PC state during instruction processing in order to put the correct address offsets in the extra words.

    is that the PC is automatically incremented as part of fetching an extension word, so does the "+" cause an additional increment???

    i think it's rather an inconsistency in teh documentation. The externsion word stuff is MSP430X/X2 while mos tof the documentation was written for the original MSP430 (non-X) instruction set.[/quote]

    I was using the term "extension word" like it's used in Wikipedia ("Instructions are 16 bits, followed by up to two 16-bit extension words"); so I really was just asking about how the PC value is referenced during basic MSP430 instruction processing -- which you have answered, although it would be good to have an exact algorithm to refer to.

    What throws me off with the "Figure 3-20 Core Instruction Map" in section 3.4.5 is that the jump instructions have codes like 20xx, 24xx, etc.


    See at it as

    001000xxxxxxxxxx to 001111xxxxxxxxxx

    or more precisely:

    001 yyy xxxxxxxxxx where 001 is the 'jump opcode' and 'yyy' is the condition and 'x' the signed offset in words.

    You never worked with a spark? There the MSB determines whether it is a call instruction (with 31 bit address in words)  or anything else.

    [/quote]

    Your explanation is good.  The "core map" (could they be more cryptic???) seems imprecise.

    so we have a 6-bit opcode, which still doesn't correspond to the 8-bit opcodes implied by "Core Instruction Map"

    the notation with hex digits dosen't allow the listing of insignificant half-nibbles. And a complete 256x256 table wouldn't help anyone :)

    However, the assembler and linker know how to build the opcodes from the mnemonics. So unless you want to write one of them (or debug them)...

    [/quote]

    I like the way Wikipedia http://en.wikipedia.org/wiki/TI_MSP430 shows the instruction set - seems totally clear as a bell.

    **** Some new questions:

    1.  Orgthogonality Question -  If you look at the SWBP instruction, the B/W field is declared as "0".  What would happen if you put a "1" in that field?

    Likewise, the RETI instruction has "00" for the As field and "0000" for the register field.  What would happen if other values were in those fields?

    2.  I notice that there is no instruction to rotate bits more than one bit location at a time.  I assume you just need to repeat the instruction for the number of bit places you want to rotate the bits.  Does this tend to eat up a lot of code memory in typical applications?  Or are bit rotations fairly rare or confined to subroutines like multipliers?  Just wondering about the choice to limit the rotate instructions.

    -SB

     

     

     

  • s b said:
    I'm still not clear on the nomenclature "@PC+"

    Actually it means that after the data fetch (with index @PC) the PC is incremented by the size of the operation (which is a word when it happens during normal microcode execution).

    However, an operation like

    mov @PC+,R15 will probably skip the next instruction, since the fetch of the source operand will increment PC before the next instruction is fetched.

    s b said:
    it seems you need to know the details of the PC state during instruction processing in order to put the correct address offsets in the extra words.

    Yes. And to make things worse, there are some differences between MSP families which are listed in the errata sheets. There are a handful operations which work different here and there (and the assembler or at least the linker needs to handle, so it needs to know the processor type -  on the PC, this is usually fixed/unified with a microcode patch in an updated board BIOS)

    s b said:
    I like the way Wikipedia http://en.wikipedia.org/wiki/TI_MSP430 shows the instruction set - seems totally clear as a bell.

    Indeed. it looks good if you are lookign at the details. However, the table in the users guide is way enough for 99% of the users, which would be rather confused by the detailed table at Wikipedia. (sometimes, users seem to be confused even by the fact that there is a users guide or a datasheet at all, and no direct google answer for their problem - complete with source code)

    s b said:
    If you look at the SWBP instruction, the B/W field is declared as "0".  What would happen if you put a "1" in that field?

    Maybe it would swap the lower byte to upper byte, but fill the lower byte with 0, therefore a <<8 instruction? Never tested. usually, a <<8 is done by clearing the upper byte (mov.b x,x) and then swapping bytes. But that's a compiler trick.
    The sign extension instruction is another such thing. It makes no sense to sign-extend a word to word size. It would be a NOP.

    Same for the call. A call with a byte operand wouldn't make much sense, there is usually no area where you can/may fetch instructions from in the range from 0x0000 to 0x00ff. And since any immediate parameter will take 16 bit even if only the lower 8 are used, this make snot much sense.

    s b said:
    RETI instruction has "00" for the As field and "0000" for the register field.  What would happen if other values were in those fields

    No idea. Maybe the return address will be moved into a different register and not to PC?

    There were several such opcodes on the old C64's 6510 processor. Some were simply not doing anything, some were crashing th emachine and some did something good, like combining two unrelated normal instructions into one, saving one instruction and one clock cycle. Soemtimes used in heavily optimized loops (such as for compression/decompression or data transfer). Side products of a shrinked/optimized microcode.

    s b said:
    I notice that there is no instruction to rotate bits more than one bit location at a time.

    There is, the RRUM instruction and its brothers. It can rotate/shift up to 4 bits in one operation. And it does not need an extension word
    s b said:
    I assume you just need to repeat the instruction for the number of bit places you want to rotate the bits.
    . For 8 bit, you can use the SWPB instruction. For everythign that exceeds 16 bit in total (e.g. long variables), you need to shift every bit on its own through carry anyway.
    s b said:
    Just wondering about the choice to limit the rotate instructions
    I can understand this. Logically, it would be an instruciton with two source parameters and one destination. Even if one of the sources is identical to the destination. It doesn't fit to the original design philosophy. However, the MSP430X instruction set now has it.

  • Thanks again.  There is more to these processors than meets the eye, as they say.  I'm sure more questions will come up as I try to program the MSP430G2231.

    1.  Can you give a detailed breakdown of the difference between:

    mov @PC+,R15

    and

    move @PC, R15

    for example?

     2.  RRUM - ok, I see in the extended instruction set.

    Do the rotate instructions do a true rotate, or are they doing a shift and padding with zeros on the trailing end?

    BTW: how did you learn the inside details about the MSP430?

    Regards,

    -SB

  • s b said:
    mov @PC+,R15
    and
    move @PC, R15

    Imho, the content of R15 will be the same. However, the first will likely skip over the word after the instruction (PC is incremented after the source is fetched). If there were a memory destination, it's likely that it would be skipped and the opcode of the next instruction would be taken as destination address.
    It's just a guess, I never tried.

    s b said:
    Do the rotate instructions do a true rotate, or are they doing a shift and padding with zeros on the trailing end

    There are four, arithmetical and logical rotates. IIRC, logical is a shift while arithmetical uses sign extension.The detailed instruction description (far below the isntruciton table in the users guide) has nice diagrams. Few people ever bother to scroll down that many pages without an entry in the bookarkstree :)

    However, a multiple-bit rol with through carry doesn't make much sense (where should the additional carry bits come from? From a different word or from itself?). However, teh nth bit that is shifted out is shifted to the carry, for what it is worth.
    For the single-bit operations, there are some more variations, which rol with carry.(RLCX? etc.)

    s b said:
    how did you learn the inside details about the MSP430

    observation, deduction and common sense, mixed with some experience, a good portion of curiosity and a little bit of inspiration. :)
    No, I don't have any insider information and din't try to decipher the inside with a microscope.
    It's not perfect, but well, if the theory and what you take from it matches the reality, it doesn't really matter whether the theory is right or wrong. Just if you observe something that doesn't match the theory, you should refine it. That's the fundamental difference between science and religion (or throwing dices)

  • There are four, arithmetical and logical rotates. IIRC, logical is a shift while arithmetical uses sign extension.The detailed instruction description (far below the isntruciton table in the users guide) has nice diagrams. Few people ever bother to scroll down that many pages without an entry in the bookarkstree :)

    You're right, I missed those diagrams -- the info is there.

    Would you confirm which document you are referencing?  I don't see an IIRC anywhere in the doc I'm reading (MSP430x2xx Family Users Guide).

    (For the most part I'm ignoring the MSP430x "extended" instructions in my questions because I don't expect to be using a processor that supports them for now.)

    Here is an interesting note in the docs about the RLA instruction:

     

    Note: RLA Substitution

    The assembler does not recognize the instruction:

    RLA @R5+, RLA.B @R5+, or RLA(.B) @R5

    It must be substituted by:

    ADD @R5+,−2(R5) ADD.B @R5+,−1(R5) or ADD(.B) @R5

    Makes me realize you have to really be on your toes working with these instructions!

    (It also highlights the curious relationship of the assembly language definition to the machine instructions.  If TI is defining the assembly language along with the processor, why can't it include that substitution as part of the assembly language!  Especially since RLA is an emulated instruction anyway!  The above note sounds more like it belongs in the errata, not in the processor guide!)

    I don't quite understand how "RLA(.B) @R5" translates to "ADD(.B) @R5"  because I don't see an "ADD" syntax with a single operand.

    The other substitutions are interesting because they directly relate to our previous discussion about when registers are incremented.  It appears that the R5 register is incremented right after the operand is fetched, in the middle of the instruction, so the destination must be indexed back a byte or word in order to add the value to itself.

    Another Question:  What exactly is the meaning/purpose of the "@" nomenclature, since it seems to only apply to source operands?  Is it equivalent to "0(Rx)", or is there some other power it has?

    Regards,

    -SB

     

     

  • s b said:
    I don't see an IIRC anywhere in the doc I'm reading

    And you shouldn't :) IIRC is an acronym and means "If I Remember Correctly".
    Anyway, I typically use the 54xx users guide, as it has the latest (and most likely most complete) documentation of informations about common topics (and it is also the one I use personally). However, the 4x, 2x and 1x users guide are also on my HD and for family-specific information and for comparisons, I usually check them too.

    s b said:
    Here is an interesting note in the docs about the RLA instruction

    Yes, there is no explicit RLA instruction at all. RLA is simulated by ADD dst, dst. (why two instrucitons when one fits both). There are several isntrucitons which have no individual opcode, such as POP, EINT, DINT, CLR and others. CLR could be emulated by MOV #0,dest as well as XOR dst,dst or SUB dst,dst. All have the same effect.

    The problem with ALL apparently one-operand instructions which are emulated with two-operand instrucitons is that you give only one parameter and addressing mode for source and destination, yet auto increment mode is only available/valid for source.

    s b said:
    I don't quite understand how "RLA(.B) @R5" translates to "ADD(.B) @R5" 

    It translates to ADD @R5+,-2(R5) or ADD.B @R5+,-1(R5). First, the source value is read from @R5, then R5 is incremented (by 1 or 2, depending on the byte/word instruction usage), then the destination value is read from @(R5-1) or @(R5-2) and the result of the addition (which is an RLA, or a multiplication by 2) is written back to @(R5-1/-2).

    s b said:
    Makes me realize you have to really be on your toes working with these instructions

    You need to just keep in mind how many accesses happen to the indexed register and therefore how many increments happen. After all, the existence of an RLA instruction is a mere convenience thing in the assembler. You could simply do without with the ADD and produce 1:1 the same binary code.

    However, I think, that this erratum is  rather based on the assenbler implementation, as the assbemler could easily recognize this and produce the correct code replacement for increment addressign mode. I guess the programmers just forgot this exception when coding the 'emulated instructions'.
    The mspgcc assembler give the error 'addressing mode is not applicable for destination operand'. Here too, the assembler programmers missed the opportunity to implement the proper replacement. But at least you'll get an error message that will tell you what's going wrong (if you think a bit about what the instruciton really does)

    s b said:
    What exactly is the meaning/purpose of the "@" nomenclature, since it seems to only apply to source operands?  Is it equivalent to "0(Rx)", or is there some other power it has?

    Yes. It's something like *R5 would be in C, while 0(Rx) is what Rx[0] would be in C. However, thelimited number of addressing mode bits has forced the development team to pick the most efficient addressing modes based on an equation of speed of one mdoe and the penalty of not having the other mode. However, 0(Rx) requires an additional offset word. Yet it's better to have this mode instead of having an indirect mode that does not allow offsetting, since it is also used ofr absolute and symbolic mode.

  • Like most microprocessors in history (and particularly the PDP-11, which started this whole "@PC+" thing), the PC is incremented as part of the instruction fetch. While the instruction is executing, the PC is the address of the following instruction. If the instruction modifies the PC, the final value is used as the fetch address for the next instruction.

    This is to common and universal that I can see how people might forget to mention it explicitly. Kind of like the stack growing downward in memory or 0-based array indexing. The fact the MSP430 works this way is quite obvious from the description of various operations.

    So the first instruction would move the word after the instruction to R15, and advance the PC past that word. Execution would continue after the data word. Thus, the net effect would be that of an immediate operand.

    The second would move the word after the instruction to R15, but not advance the PC, so execution would continue with the data word. The use of this operation is unclear, except in deliberately obscure code.

    As for me, it all came from RTFM.

  • I don't see an IIRC anywhere in the doc I'm reading

    And you shouldn't :) IIRC is an acronym and means "If I Remember Correctly".[/quote]

    I'm still ROTFLOL!


    What exactly is the meaning/purpose of the "@" nomenclature, since it seems to only apply to source operands?  Is it equivalent to "0(Rx)", or is there some other power it has?

    Yes. It's something like *R5 would be in C, while 0(Rx) is what Rx[0] would be in C. However, thelimited number of addressing mode bits has forced the development team to pick the most efficient addressing modes based on an equation of speed of one mdoe and the penalty of not having the other mode. However, 0(Rx) requires an additional offset word. Yet it's better to have this mode instead of having an indirect mode that does not allow offsetting, since it is also used ofr absolute and symbolic mode.

    [/quote]

    Ok, I think I see -- @R1 does not require the extra offset word, and only applies to the source operands because they ran out of addressing mode bits (only 1 bit for Ad field in the double operand instructions), otherwise they could have had an equivalent for the dest operand.  So it is a nomenclature that lets us tell the assembler the most efficient way to use a register as an address.

    Thank you for these detailed discussions, they really help.

    I am now slowly getting familiar with using the TI CCS assembler/compiler to program the MPS430G2231 and MPS430G2211 that came with the Launchpad (I'm mainly interested in the 2231 to begin with).

    My first questions have to do with learning the rules involving the use of RAM, such as how the stack pointer (SP) is initialized, what variables are assigned to RAM and where, how would one store data in the Flash Memory if necessary.  The compiler and debugger hide a lot of stuff I'd like to see explicitly, so I need to get familiar with how to expose it and examine it.

    I would also like to be able to use the system to load machine code directly into the MPS430 flash memory and/or RAM and start it running so I could try hand-assembling some code -- crazy I know but somehow makes it more real.

    Regards,

    -SB

     

  • s b said:
    My first questions have to do with learning the rules involving the use of RAM, such as how the stack pointer (SP) is initialized, what variables are assigned to RAM and where,

    Initializing the stack pointer is part of the C startup code, as well as copying initialized variables from flash to ram. THis is compiler-dependent. There's a reason why the compiler hides this kind of things: it 100% depends on how the compiler compiles the C code. Messing with it is highly dangerous and usually unneeded.

    I must admit that I once wrote my own reset function for the mspgcc (the original was disabling the WDT to avoid timeouts while copying the variables, which was inacceptable for my project)

    If you program directly in assembly language, it's up to you to init the stack pointer: Just move its initial value into R1. That's all.

    s b said:
    how would one store data in the Flash Memory if necessary.

    That's a different baby and there are several (many) threads discussing this.

    s b said:
    I would also like to be able to use the system to load machine code directly into the MPS430 flash memory and/or RAM and start it running so I could try hand-assembling some code -- crazy I know but somehow makes it more real.

    Well, I understand this. When I started programming on the 6510 (C64), I wrote my first assembly programs with nothing than a disassembler with integrated one-line assembler (assembly monitor). Lien by line. No macros, labels etc. Barely more than putting values into ram. And it worked sooner or later (sooner it was workign later, later it was working sooner)

    The elprotronic programming software is able to program a plain hex file to the MSP. (or MSPGCCs MSP430-JTAG, but it cannot handle the newer processors, a tleast not the version I have). You can produce your output in binary form and let it write to the MSP if you really want.

  • I guess I'm wondering -- where do you typically initialize the stack pointer in assembler -- to the highest address in RAM?  And in C (and assembler), how do you keep the stack from overwriting static variables, or simply running out of RAM?  Or at least have a clue how to manage RAM when there is so little of it and the stack is eating into it?  Seems like a lot of thought and planning might go into managing RAM.

    It will take some time to look through the C library to see what is available, such as heap storage allocation, math functions, what are the speed and size considerations of the math functions, what precision arithmetic can be done reasonably efficiently, etc.

    I'll be slowly looking at at these issues and will hopefully post some better-informed questions as time goes on.

    Thanks for the guidance.

    -SB

     

     

  • s b said:
    where do you typically initialize the stack pointer in assembler -- to the highest address in RAM?

    Usually, yes. Except you want some space where you can keep variables that are not re-initialized on a reset. At least ont he MSPGCC, this is an appropriate way: reserve some bytes above the stack and point your variables there. Then you have, e.g. continuous counters even if the device resets (not across a power-off, of course, but maybe a brownout, or if you have ESD problems etc... or simple wrote you code that the device resets itself under certain conditions, but want to keep data without writing to flash)

    s b said:
    And in C (and assembler), how do you keep the stack from overwriting static variables, or simply running out of RAM?

    Not at all. The stack gros as the stack is told so by the program flow.
    IAR offers a 'stack size' feture that 'reserves' some ram for the stack. But this only tells the linker to throw an error if your variables allocate so much ram that less than the configured amoutn remains. It does not, however, limit the stack. And how shoudl this work? Even if the stack would reach a certain limit, what ashall the cpu do? Entering an NMI ISR would require more stack space. The only possible action would be a reset. The debugger (in debugging mode) perhaps places a breakpoint on this stack register value, so the breakpoitn is hit when the stack pointer reaches this limit. Without debugger control, teh stack will grow until it reaches non-ram area and the system crashes (if it hasn't before because of overwritten variables or variables overwriting the stack that has grown to their location).

    s b said:
    what precision arithmetic can be done reasonably efficiently

    Efficiently: any. Just not conveniently. Using float or double is slow. Multiplications and divisions are even slower.
    Creative usage of integers is much more efficient. And if you need fractions, you can use the Q-numbers.
    On newer MSPs, there is a 32 bit hardware multiplier which can even do multiuply-accumulate with a 64bit result from a 32 bit operation. C however, allows only 32 bit results from 32 bit operations and 64bit results from 64bit operations, is therefore inherently inefficient. Using optimized assembly code brings huge benfits here.
    The MSP is no high-level math-wizard.

    Also, depending on the used compiler, the available implementations greatly differ. Much of the standard C library doesn't make much sense on an MSP (such as stdio, as there is no such thing liek a standard input or output). CCS, IAR and MSPGCC implement different subsets and to a different extent. Of course you can take any high-level source code for an STDLIB implementation and compile it for the MSP.

  • Thanks for the tips!  I'll have to look into Q-numbers.  Also probably should brush up on my "twos-complement" arithmetic, etc.

    I'd like to do some A to D sampling and some digital low-pass or low band-pass filtering of the signal.  I think it will be very tight for time with an MSP430, so probably I'll need to use some tricks rather than straight math.  I'd like to sample at the maximum rate (200K p/s) but I'm pretty sure there wouldn't be enough computation time.  So I'll probably use some analog integration and sample around 15K p/s, but even then probably very tight for computation time.

    Do you know anything about the "sample and hold" modes of the MSPG2231?  The family manual refers to "Sample-and-hold with programmable sample periods", and I'm wondering what that really means.

    Regards,

    -SB

  • s b said:
    I'd like to sample at the maximum rate (200K p/s) but I'm pretty sure there wouldn't be enough computation time.

    Depends on the formula you use and how you program it. Remember, instead of dividing, you can multiply and then shift down. So instead of dividing by 1000, multiply with 1.024 (or live with the difference) and then shift right 10 bits. Is some magnitudes faster. With this kind of tricks you can speed up computations very much. But keep track of the value range (e.g. use long ints etc.)

    The ADC10/12 is an SA converter. It samples the input signal to a storage capacitor, then cuts off the connection to the input and does a successive approximation. It compares the stored value to Vref/2, then (based on teh result of this comparison) to Vref/4 or Vref/2+Vref/4 etc. MSB down to LSB. The hold time (tiime for the conversation itself) is n+1 clock cycles  (where n is the requested number of bits for ADC12A, for ADC10, it is fixed 13 clock cycles). But the preceding sampling time can be adjusted.

    The input forms a low pass (sereis resistor and storage capacitor), so the longer you hold the input open, the more time the signal has to settle (for high-impedance sources) or to form an average (low-pass effect). With the ADC10SHTx bits in ADC10CTL0 can you define how many clock cycles this sampling period shall last.

    Also, you can make your individual timing by directly controlling the input switch using a timer CCRx output or an external signal. Switch closed: sampling. Switch opened: begin converting (and 13 clock pulses later the result is provided). Gread for keeping the CPU in sleep mode and still gettign precisely timed conversion results.

     

  • Thanks for the good info.  I need to collect some of those numerical tricks.  I think I'll need 32 bit accumulators, if not 64 bit for my aps.

    Sounds like I might be able to use the ACD10CTL0 to do some integration, need to know a little more about the series resistor and storage capacitor and how they are controlled.

    The timer for the conversion sounds like it would be what I need for one version of the application I'm thinking of.

    What about the idea of a "tracking" ADC, where the max and min levels of the ADC are adjusted to follow the waveform, in the hopes of faking more precision?

    What kinds of applications do you use the MSP430 for?

    Regards,

    -SB

  • s b said:
    What about the idea of a "tracking" ADC, where the max and min levels of the ADC are adjusted to follow the waveform, in the hopes of faking more precision?

    This kind of ADCs is useful if you have slowly changing signals. However, teh conversion time depends on the signal change speed, so if you switch channels or have high-frequency signals, conversion speed goes significantly down.
    A different approach are the Delta-Sigma converters (e.g. the SD16 in some 2x and 4x devices). Those those integrate the incoming signal and compare the integrated signal to the reference, outputting a '1' or '0' bit with every clock cycle. Depending on the last conversion result, thereference is suptracted from teh output or not. So the percentage of '1' bits in the output stream equals the percentage of the input signal compared to the reference. Basically, after two clock cycles you can tell whether the signal is above or below 50%. The MSPs SD16 puts at least 32 bits into a digital filter (maximum is 1024) and gives you a 16 bit result (with varying number of significant bits, depending on this oversampling ratio). However, when switching channels, a certain number of results is invalid.

    To increase the results of the AD10/AD12, you can modulate a small (best: 1LSB worth), high-frequency signal to the input. Then you sample several times (at least over one complete cycle of this signal) and build an average. The signal will shift the input voltage 'over the edge' to the next higher bit, but only for some fractions of its wavelength. So the average of several amples during one wave gives you additional significant bits, even if the input signal is static and would otherwise give you always exactly the same value.

    (sometimes, signal noise does the same for you, but then you don't know th eperiod and therefore the exact magnitude of its influence)

    s b said:
    What kinds of applications do you use the MSP430 for?

    We have an energy meter (up to 1.3MW, industrial use), datalogger and wireless transmitter, and an interface for analog/pulse/4-20mA external sensors (complete with visualisation software for the PC, which I also work on). And a power supply and modulation controller for a high-power show laser (up to 8W laser output, up to 30kHz full analog modulation).
    There have been some side-projects, e.g. a radio-controlled relay card (8 radio-controlled high-voltage air gap switches), including a logic for gathering energy consumption information over a certain period and controllign a 'traffic light' and switching off machines when the projected energy consumption will exceed a certain limit in a 1/4 hour period (this value is important for the base fee charged by the energy provider: the highest value in a month determines the base fee for the next month (or even year), so exceeding the current limit will increase the monthly costs by 10k of Euros.)
    There has also been a home automation project (X-10 based) but most of the devices were built with PICs, only one (the last one) was MSP based and the whole home automation thing has been dropped years ago.
    My colleague had a private project: auto-pilot for a helicopter. Involving 3 3-axis acceleration sensors for detecting all kinds of movement and rotation. The chopper was hovering in teh air without any user intervention. It would even stop (and return to the old position) if you give it a kick. However, the MSP1232 he was using was too small to house all functions at the same time, so the project silently died some years ago. He just didn't find the time to design a new PCB for a bigger MSP etc.

  • Those are some interesting projects you have worked on!  These microcontrollers have a lot of potential due to their low cost and low power.

    Thanks for the ADC info - I suspect I will eventually wish I was using at least a 16 bit ADC, but I'll try whatever tricks I can with the 10 bit ADC.  You mentioned the "dithering" technique with the small extra signal.  There will be some natural noise in the system that may work in that regard.  Although I want to sample at at least 15K p/s, the extracted signal is quite low frequency, maybe 10 Hz, so the digital filter will be doing the "averaging". 

    Now, the digital filter is another question.  I'd like to start with a really simple filter, like Yt = .99 * Yt-1+ .01 * Xt , but even that arithmetic may strain the processor.

    I saw an impressive MSP430 filtering example in a paper called "

    Wave Digital Filtering Using the MSP430" by Kripasagar Venkat -- way over my head at this time.

    So I'll little-by-little try to get my feet wet with this microcontroller - it will go slow due to other priorities.

    Regards,

    -SB

  • s b said:
    These microcontrollers have a lot of potential due to their low cost and low power.

    Yes. While the power isn't an issue in out projects (if you do energy metering, there's an unlimited power source nearby). Our main reason for chosing them was the ability to be programmed in-circuit, the low count on required external components and the high integration of well-assembled hardware modules. Even the price wasn't a big issue.
    It did, however, help that a former colleague already had some MSP experience and that the mspgcc compiler was free (when this all started, we didn't have much money for tools, even if the production costs weren't an issue)
    I'm happy we got away from those dreaded PICs.

    s b said:
    like Yt = .99 * Yt-1+ .01 * Xt , but even that arithmetic may strain the processor.

    Well, try Yt= (1014*Yt-1+Xt)>>10. (it's the same except a 0.2% error, and may be further refined)

  •  

    Ultra-low power is not a main issue for my application either, even though the application is battery-powered.  However, it makes me want to think of other ideas that might take advantage of such stingy power use.  Of course, most of the power savings are due to the low-duty modes, so that limits the aps somewhat.  Anyway, I hope this microcontroller is worth investing some time in -- I got sucked in by the Launchpad, which I think is a great way to market these devices.  If IBM had given OS/2 away free to college students, who knows what would be running on PCs today!

    try Yt= (1014*Yt-1+Xt)>>10. (it's the same except a 0.2% error, and may be further refined)

    Exactly the kind of useful tip I'm interested in.  Thanks!

    -SB

     

  • s b said:
    try Yt= (1014*Yt-1+Xt)>>10. (it's the same except a 0.2% error, and may be further refined)

    [/quote]It's actually Xt*10 :)

    The basic idea was to multiply the fractions by 1024 and the divide the result by 1024, which is a simple shift.
    You can reduce the error by multiplying/shifting with 2048 or 4096, if the result of the idividual multiplication operations still fits into a long variable.

    s b said:
    Exactly the kind of useful tip I'm interested in

    Sometimes precision isn't as important as speed. Many people tend to forget it. The same people who use FFT instead of the way more accurate but by magnitudes slower default Fourier Transformation. :)

    One key rule for MSPs (and othe rmicrocontrollers) is: "If you can do it at compiletime, don't do it at runtime".  Another one is " keep things simple. And if they are not simple, make them simple"
    It would fit well for normal PC programs too. But for microcontrollers, it is essential.

**Attention** This is a public forum