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.

MSP430F2410 Multiplier Issue

Other Parts Discussed in Thread: MSP430F2410, CCSTUDIO

Hello,

I am trying to perform a multiplication of two 16 bit unsigned numbers using the Multiplier.  Sounds simple, right.  So I am doing this at the chip level via the JTAG port using waveforms from an automated tester. 

Anyway, I am setting the MPY register 0x0130h to 8000h and the OP2 register 0x0138h to 8000h.  I toggle MCLK a few times and get RESLO(0x013Ah) = 7F80h, RESHI(0x013C) = 4000h, and SUMEXT(0x013E) = 0000h.

The issue is the RESLO should be 0000h.  It is essentially off by little less than one.  Basically 8001h x 8000h - 80h = 40007F80h.

Any ideas what might be happening.  Here is my JTAG command sequence (The second value on some of the DR_SHIFT16 commands are the value that I am comparing against):

ResetTAP
IR_SHIFT("IR_CNTRL_SIG_16BIT")
DR_SHIFT16(0x2C01) : Apply Reset
DR_SHIFT16(0x2401) : Remove Reset
ClrTCLK
SetTCLK
ClrTCLK
SetTCLK
ClrTCLK
IR_SHIFT("IR_ADDR_CAPTURE") : read JTAG ID
SetTCLK
IR_SHIFT("IR_CNTRL_SIG_CAPTURE") : Wait for CPU in instr fetch state
DR_SHIFT16(0x0000)(0x2681)
ClrTCLK
SetTCLK
IR_SHIFT("IR_DATA_16BIT")
DR_SHIFT16(0xC232) : "DINT" Disable Interrupt
ClrTCLK
SetTCLK
IR_SHIFT("IR_CNTRL_SIG_CAPTURE") : Wait for CPU in instr fetch state
DR_SHIFT16(0x0000)(0x2681)
ClrTCLK
SetTCLK
IR_SHIFT("IR_DATA_16BIT")
DR_SHIFT16(0x4303) : "NOP"
ClrTCLK
SetTCLK
IR_SHIFT("IR_CNTRL_SIG_CAPTURE") : Wait for CPU in instr fetch state
DR_SHIFT16(0x0000)(0x2681)
ClrTCLK
SetTCLK
IR_SHIFT("IR_DATA_16BIT")
DR_SHIFT16(0xC312) : "CLRC"
ClrTCLK
SetTCLK
IR_SHIFT("IR_CNTRL_SIG_CAPTURE") : Wait for CPU in instr fetch state
DR_SHIFT16(0x0000)(0x2681)
ClrTCLK
SetTCLK
IR_SHIFT("IR_DATA_16BIT")
DR_SHIFT16(0x3FFF) : "JMP $" instruction to keep CPU from changing the state
ClrTCLK
IR_SHIFT("IR_CNTRL_SIG_16BIT")
DR_SHIFT16(0x2409) : set HALT_JTAG bit
SetTCLK
ClrTCLK
IR_SHIFT("IR_CNTRL_SIG_16BIT") : Disable Watchdog
DR_SHIFT16(0x2408) : Set to Write
IR_SHIFT("IR_ADDR_16BIT")
DR_SHIFT16(0x0120) : Set Watchdog Control Register Address
IR_SHIFT("IR_DATA_TO_ADDR")
DR_SHIFT16(0x5A80) : Write to Watchdog Control Register
ClrTCLK
SetTCLK
IR_SHIFT("IR_CNTRL_SIG_16BIT")
DR_SHIFT16(0x2408) : Set to Write
IR_SHIFT("IR_ADDR_16BIT")
DR_SHIFT16(0x0130) : Set Operand One - Multiply MPY for 16x16 Unsigned Multiply
IR_SHIFT("IR_DATA_TO_ADDR")
DR_SHIFT16(0x8000) : Write to MPY 8000
SetTCLK
ClrTCLK
IR_SHIFT("IR_CNTRL_SIG_16BIT")
DR_SHIFT16(0x2408) : Set to Write
IR_SHIFT("IR_ADDR_16BIT")
DR_SHIFT16(0x0138) : Set Operand Two - OP2 for 16x16 Unsigned Multiply
IR_SHIFT("IR_DATA_TO_ADDR")
DR_SHIFT16(0x8000) : Write to OP2 8000
SetTCLK
ClrTCLK
SetTCLK
ClrTCLK
SetTCLK
ClrTCLK
SetTCLK
ClrTCLK
SetTCLK
ClrTCLK
IR_SHIFT("IR_CNTRL_SIG_16BIT")
DR_SHIFT16(0x2409) : Set to Read
IR_SHIFT("IR_ADDR_16BIT")
DR_SHIFT16(0x013A) : Set Address for Result Low - RESLO
IR_SHIFT("IR_DATA_TO_ADDR")
SetTCLK
ClrTCLK
DR_SHIFT16(0x0000)(0x0000) : Read Low Word - RESLO
IR_SHIFT("IR_CNTRL_SIG_16BIT")
DR_SHIFT16(0x2409) : Set to Read
IR_SHIFT("IR_ADDR_16BIT")
DR_SHIFT16(0x013C) : Set Address for Result High - RESHi
IR_SHIFT("IR_DATA_TO_ADDR")
SetTCLK
ClrTCLK
DR_SHIFT16(0x0000)(0x4000) : Read High Word - RESHI
IR_SHIFT("IR_CNTRL_SIG_16BIT")
DR_SHIFT16(0x2409) : Set to Read
IR_SHIFT("IR_ADDR_16BIT")
DR_SHIFT16(0x013E) : Set Address for Sum Extension - SUMEXT
IR_SHIFT("IR_DATA_TO_ADDR")
SetTCLK
ClrTCLK
DR_SHIFT16(0x0000)(0x0000) : Read Sum Extension - SUMEXT
SetTCLK
ClrTCLK

  • Did you try to use "normal" way of multiplication? - By writing code, loading it into msp430? Same results?

  • Not yet.  Apparently the MSP430F2410 is not supported after CCSv3.3.  So I had to purchase a full version of CCS5 to get a copy of CCSv3.3.  I have now installed CCSv3.3, but there are no drivers for the MSP430 products.  I also have the MSP-FET430UIF.  Apparently I can add more device types once I register CCSv3.3, but I can't register CCSv3.3 because I don't have a service code since it is so old. 

    So I am back to trying to make this work via creating JTAG waveforms on the test system.

  • Tom N said:
    So I am back to trying to make this work via creating JTAG waveforms on the test system.

    You shall consider IAR compiler then. There's code-size limited version and time-limited evaluation either.

  • Tom N said:
    Apparently the MSP430F2410 is not supported after CCSv3.3.

    ???

    The current verison of CCS should support all MSPs.

    The only thing is that previous CCS version (or rather the MSP430.DLL) used virtual COM port drivers to communicate with the FET, while the latest generation uses CDC drivers and requires an update of the FET firmware as well as an update of the system drivers for the FET (you might need to uninstall the old and manually install the new drivers)

  • Actually, if you look at the fine print on TI's CCS5 page you will see a note at the bottom saying that F24x devices require CCSv3.  I have tried v4 and v5.  Both version will light the power LED on the board, but do not recognize the device.

    Additional Information
  • Tom N said:
    For F24x/C24x devices - Requires Code Composer Studio v3

    IIRC, this referes to TMS320F24x/C24x devices, and not MSP430. See here.

    Also, if you follow the link in your own post, and read the description of this CCS3.3, you'll see

    "TMDSCCS2000-1 v3.3 for F24x/C24x Devices - Code Composer Studio™ (CCStudio) v3 is an integrated development environment (IDE) for Texas Instruments' (TI) TMS320F24x/TMS320C24x embedded processors."

    The TMS320F24x deices are discontinued and superseded by the TMS320F28x. SO support for them was removed on newer CCS versions. However, the MSP430F24x are active products and supported by the current CCS.

    Maybe you can get your money back.

  • Hmm.  I guess my issue is that I need to figure out why CCS5 doesn't recognize my device.  I am using the TI MSP-FET430UIF and a Scmartboard application board.  I'll start a new thread since this topic isn't related to my initial Multiplier question.

    http://www.schmartboard.com/index.asp?page=products_dev&id=331

  • I now have CCS5 working with the MSP430F2410.  The reset wasn't properly connected.  I will take a look at the multiplication code later this evening or tomorrow.

  • Back to the original problem.  I am using JTAG to load a value into MPY and a value into OP2.  Then I am reading back RESLO, RESHI, and SUMEXT, but I am getting the wrong values.  If I compile a program to perform the same operation in CCS5 and upload it to the device it works fine.  I can't upload all of the tests though because it takes too long.

    Here are my test results (any thoughts of what might be wrong?)

                                            Expected   Measured
    14000 MPY 16x16 0x0000h*0x0000h Reslo     0.000      0.000   Pass
    14001 MPY 16x16 0x0000h*0x0000h Reshi     0.000      0.000   Pass
    14002 MPY 16x16 0x0000h*0x0000h Sumext    0.000      0.000   Pass

    14005 MPY 16x16 0x7FFFh*0x7FFFh Reslo     1.000    16.256K   FAIL
    14006 MPY 16x16 0x7FFFh*0x7FFFh Reshi   16.383K    32.766K   FAIL
    14007 MPY 16x16 0x7FFFh*0x7FFFh Sumext    0.000      0.000   Pass

    14008 MPY 16x16 0xFFFFh*0xFFFFh Reslo     1.000    32.512K   FAIL
    14009 MPY 16x16 0xFFFFh*0xFFFFh Reshi   65.534K    65.534K   Pass
    14010 MPY 16x16 0xFFFFh*0xFFFFh Sumext    0.000      0.000   Pass

    14011 MPY 16x16 0x7FFFh*0xFFFFh Reslo   32.769K    16.256K   FAIL
    14012 MPY 16x16 0x7FFFh*0xFFFFh Reshi   32.766K    32.766K   Pass
    14013 MPY 16x16 0x7FFFh*0xFFFFh Sumext    0.000      0.000   Pass

    14014 MPY 16x16 0x8000h*0x7FFFh Reslo   32.768K    32.640K   FAIL
    14015 MPY 16x16 0x8000h*0x7FFFh Reshi   16.383K    32.767K   FAIL
    14016 MPY 16x16 0x8000h*0x7FFFh Sumext    0.000      0.000   Pass

    14017 MPY 16x16 0x8000h*0xFFFFh Reslo   32.768K    32.640K   FAIL
    14018 MPY 16x16 0x8000h*0xFFFFh Reshi   32.767K    32.767K   Pass
    14019 MPY 16x16 0x8000h*0xFFFFh Sumext    0.000      0.000   Pass

    14020 MPY 16x16 0x8000h*0x8000h Reslo     0.000    32.640K   FAIL
    14021 MPY 16x16 0x8000h*0x8000h Reshi   16.384K    32.639K   FAIL
    14022 MPY 16x16 0x8000h*0x8000h Sumext    0.000      0.000   Pass

  • What's the point to run multiplier using jtag?

  • I have to write a test program to test the MSP430F2410 at the chip level on automated test equipment.  I have the tests completed for all the I/O pin states, Comparator, and ADC12.  I am now on Multiplier.  It seems pretty straightforward.  1) Stop the CPU 2) Stop the Watchdog Timer  3) Send a 16 bit word to MPY.  4) Send a 16 bit word to OP2 5) Read back RESLO  6) Read back RESHI  7) Read back SUMEXT. 

    Since I am in JTAG mode and I am supplying the clock via TCLK.  I have tried supplying as many as 100 TCLKs between loading MPY and OP2 and reading the results.  But the result data always seems to be corrupt.

    I verified that the device is working by writing a program in CCS5 and saving is as TI-TXT.  Then I developed a test pattern to load the values into flash and reset the device.  Using this method produces the correct result, but it takes 15 seconds to load the code which is far too long for an automated test program.

    The CCS5 version of the program is very basic:

    #include <msp430.h>

    int main(void)
    {
      WDTCTL = WDTPW+WDTHOLD;               
      MPY = 0x8000;                          
      OP2 = 0x8000;                           
      _BIS_SR(LPM4_bits);                  
    }

  • Tom N said:
    t takes 15 seconds to load the code which is far too long for an automated test program.

    It is far too long. For any putpose. In 15 seconds (or rather, in less than 10), I can upload even out bigger programs, using MSP430-JTAG (which uploads a 'flash the MSP' code and data and then executes it, 2k data at a time).
    So I wonder what takes so long to upload a few bytes of code?

    It's indeed strange that the MPY isn't workign this way. One thing I could imagine is that you are stuffing OP2 too fast. When using JTAG, you can write OP2 on the next MCLK cycle after writing MPY. When using the CPU or DMA, it takes at least two cycles (DMA: one fore reading the word, one for ewriting, CPU: one for reading the writ einstruction, and one fore readign the address or the offset for indexed write, even if the value itself is in a register)
    So except for JTAG, it is impossible to write OP2 on the next cycle after MPY. Maybe nobody ever tried it with JTAG and this is an unknown limitation ofthe MPY? Try adding two waitstates between writing MPY and OP2.

  • Thanks for the feedback.

    I have already tried adding wait states in various locations.  I have tried just time delays and additional TCLK pulses.  What I have found is that the only place that is impacted is the time between loading the two values in memory and reading the results back.  It takes somewhere between two and ten TCLK cycles to process.

    I am having some issues with reading and writing RAM as well using my JTAG test patterns.  I can read the ID bits with no issues.  I can read and write Flash with no issues.  However, when I write to RAM, I can read back the value only if it is the next thing I do.  If I write more values to RAM, then try to read, all location will contain the same value.  If I ping pong between main and extended RAM, the values change but are still incorrect.

    I am thinking these two issues may be related, so I am going to go through my JTAG pattern for the Multiplier and compare it line by line with a JTAG state diagram to make sure everything appears fine.

    Tom

  • Does the CCS5 compiler automatically handle the wait states?  Here is my CCS5 program equivalent that I have uploaded onto my project board and it is also giving bad results.  This is running on a new MSP430F2410 that I just received from TI.

    #include <msp430.h>
    char *RAM_Pointer;
    unsigned int Value[14];
    unsigned int Result[21];
    int j;

    int main(void)
    {
      WDTCTL = WDTPW+WDTHOLD;                   // Stop WDT

      Value[0] = 0x0000;     //MPY
      Value[1] = 0x0000;     //OP2
      Value[2] = 0x7FFF;     //MPY
      Value[3] = 0x7FFF;     //OP2
      Value[4] = 0xFFFF;     //MPY
      Value[5] = 0xFFFF;     //OP2
      Value[6] = 0x7FFF;     //MPY
      Value[7] = 0xFFFF;     //OP2
      Value[8] = 0x8000;     //MPY
      Value[9] = 0x7FFF;     //OP2
      Value[10] = 0x8000;     //MPY
      Value[11] = 0xFFFF;     //OP2
      Value[12] = 0x8000;     //MPY
      Value[13] = 0x8000;     //OP2


      MPY = Value[0]; // Load first operand -unsigned mult
      OP2 = Value[1]; // Load second operand
      Result[0] = RESLO;
      Result[1] = RESHI;
      Result[2] = SUMEXT;
      MPY = Value[2];                             // Load first operand -unsigned mult
      OP2 = Value[3];                             // Load second operand
      Result[3] = RESLO;
      Result[4] = RESHI;
      Result[5] = SUMEXT;
      MPY = Value[4];                             // Load first operand -unsigned mult
      OP2 = Value[5];                             // Load second operand
      Result[6] = RESLO;
      Result[7] = RESHI;
      Result[8] = SUMEXT;
      MPY = Value[6];                             // Load first operand -unsigned mult
      OP2 = Value[7];                             // Load second operand
      Result[9] = RESLO;
      Result[10] = RESHI;
      Result[11] = SUMEXT;
      MPY = Value[8];                             // Load first operand -unsigned mult
      OP2 = Value[9];                             // Load second operand
      Result[12] = RESLO;
      Result[13] = RESHI;
      Result[14] = SUMEXT;
      MPY = Value[10];                             // Load first operand -unsigned mult
      OP2 = Value[11];                             // Load second operand
      Result[15] = RESLO;
      Result[16] = RESHI;
      Result[17] = SUMEXT;
      MPY = Value[12];                             // Load first operand -unsigned mult
      OP2 = Value[13];                             // Load second operand
      Result[18] = RESLO;
      Result[19] = RESHI;
      Result[20] = SUMEXT;


      RAM_Pointer = (char *)0x1120;           // Point to beginning of data segment
      for (j = 0; j < 21; j++)
        *RAM_Pointer++ = Result[j];           // Save result data
      _BIS_SR(LPM4_bits);                       // LPM4
    }

    Here are the results in memory:

    RAM_Pointer
    1135
    Value
    0000    0000    7FFF    7FFF    FFFF    FFFF    7FFF    FFFF    8000    7FFF    8000    FFFF    8000    8000
    Result
    0000    0000    0100    00FF    FE01    0100    00FE    FF00    0000    00FF    0000    0000    8000    3FFF    0000    8000        7FFF    0000    0000    4000    0000
    j

  • The results should be:

    0000 0000 0000 0001 3FFF 0000 0001 FFFE 0000 8001 7FFE 0000 8000 3FFF 0000 8000 7FFF 0000 0000 4000 0000

  • Well, I found the error in my test program.  There was a mistake in the way the JTAG pattern was generated at the waveform level.  The issue has been corrected and the MPY test is now working.

    Thanks

  • Edit: This refers to the test program uploaded to the MCU rather than the JTAG test sequence.

    The elements of the Result array are of type int, but RAM_Pointer is of type char*. It looks like the assignment *RAM_Pointer++ = Result[j]; might be truncating your result values to 8 bit.

    How are you viewing the results, by the way? Are you pausing the program in the CCS debugger and viewing the memory there?

  • Robert Cowsill said:
    How are you viewing the results, by the way?

    That's a good question. Sometimes DEC applies (double error correction - an error in transmission is 'corrected' by the same error in opposite direction, so verification seems to be okay).
    Which apparently was the case here.

    So for verification, a different method should be used than for transmission. Unless you are sure that the transmission does work 100%.

  • Robert Cowsill said:

    How are you viewing the results, by the way? Are you pausing the program in the CCS debugger and viewing the memory there?

    Yes, I am using the CCS5 debugger.  I execute and pause the program.  Then under "View," I select "Memory Browser."  In the memory browser window, I type the start of the memory location that I would like to see and press "Go."

**Attention** This is a public forum