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.

Problem msp430: control 3 motors

Other Parts Discussed in Thread: MSP430F2274

Right now I got a litlle bit stuck on the following project:
I´m trying to control 3 motors at the same time with the msp430. The speed will be regulated with PWM, and the input I will want to control it with 3 potenciometers. One POT for each motor. The way that I´m trying to  do that is using de DTC to store 3 samples, one sample of each POT and read it back using ADC10SA pointer. Each value of the POT will be converted directly to the PWM duty cicle.
So, therre is something that will not work, when I hook it up I´ll see a wierd square wave (I think in P2.3), with some strange duty cicle, and it will romain constant even if we vary the POT's. And in the other 3 PIN´s that should give me some more PWM do not respond.
Could someone please tell me why?
Thank you so much in advance for all your time.

CODE:


#include "msp430x22x4.h"

unsigned int DATA[3];

void main(void){
   
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
 
  //ADC SETTINGS
  ADC10CTL1 = INCH_2 + CONSEQ_1;    // A2/A1/A0, single sequence
  ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
  ADC10DTC1 = 0x03;                //3 Conversions
  ADC10AE0 |= 0x07;                //Set A2 A1 and A0 as ADC10 inputs
 
  //PWM SETTINGS
   P2DIR |= 0x18;        //Setting P2.3 and P2.4 as outputs
   P2SEL |= 0x18;        //Selecting the special function of P2.3 and P2.4 for the PWM
  
   P4DIR |= 0x10;        //Setting P4.4 as output
   P4SEL |= 0x10;        //Selecting the special function of P4.4 for the PWM
  
   TACCR0 |= 1023;        //setting duty period of TimerA
   TBCCR0 |= 1023;        //setting duty period of TimerB
   TACCTL1 = OUTMOD_7;
   TACCTL2 = OUTMOD_7;   
   TBCCTL1 = OUTMOD_7;
 
  //Program initialitzation
   
  for(;;){

    //Sampling ADC10
      ADC10CTL0 &= ~ENC;       
      while(ADC10CTL1 & BUSY);    //Wait if the ADC10 core is active
      ADC10SA = (unsigned short)&DATA;
      ADC10CTL0 |= ENC + ADC10SC;     // Sampling and conversion start
      ADC10CTL0 &= ~ENC;
    ADC10CTL0 = 0;                    // Power down the ADC
   
    //Setting PWM
    TACTL = TASSEL_2 + MC_1;
    TACCR1 = DATA[3];
    TACCR2 = DATA[2];
    TBCTL = TBSSEL_2 + MC_1;
    TBCCR1 = DATA[1];
  }
}

  • My recommendation would be the following:
    1. Use a TI Target board:
    http://focus.ti.com/docs/toolsw/folders/print/msp-ts430da38.html

    2. Test the code example (msp430x22x4_ta_16.c) from the following link:
    http://www.ti.com/lit/zip/slac123

    Check to see if you get a good PWM output.

    3. Separately test the code example (msp430x22x4_adc10_07.c) in the above zip file link and check to see if the values are being read correctly by the ADC and stored by the DTC.

    4. Then combine the two code examples to test a basic scenario.

    This will help isolate the issue to software/hardware or device related.

  • First of all, thank you very much for the respons.

    I must admit that if done quite allot of code's with different PWM all of them working. The problem is the ADC10 storage.

    In example 7 shows how to store it,  but it doesn't show how to read back. 

    I supose you recomend this TI target board, but right now I'm in a lab with allot of osciloscopes and power supplies.

    Example msp430x22x4_adc10_18, gets close at my question, but it's not working, only P1.3 is working.

    I guess my question is: how can I read back the adc10 data that I stored in the DTC?

  • Hi RIV,

    have a look at the example code i've posted under 'My files' (http://e2e.ti.com/members/1371069/files/default.aspx). I'm using DTC for dealing with my ADC samples. The results were stored in a seperated segment in RAM (look at the .cmd file(!) how to do this).

    Rgds
    aBUGSworstnightmare

  • Hi aBUGSworstnightmare:


    Thank you allot for your reply, but I must admit that I really do not understand your code, with all diferent functions and heather files. Could you maybe point me out some part of the code? I developed a code, that I saw from someone else on the web and modified it a little bit, it looks like the defined array is completly worthless, but if I take that away, I'll get my PWM outputs "moved". So what I should get fromo pin2.3, I'll get it from P2.4, etc...

    So actually this code is not very effective, so I'll still apreciate some DTC's or some more eficient way to do it (maybe you aBUGS?). But I want to publish it just because it works and maybe I can help someone for some really quick solution:

     

    "

    //PIN CONFIGURATION.
    //==================
    //In this program we are going to record 3 adc manually each time and we are going to give the respective PWM
    //each of the 3 ADC10 inputs.
     
    //PIN CONFIGURATION.
    //==================
    //PIN6 PIN7 and PIN9 (P2.3, P2.4 and P4.4) will do the PWM output. P2.3 TA1, P2.4 TA2 and P4.4 TB1.
    //PIN3 PIN4 and PIN5 (P2.0, P2.1 and P2.2) will do the ADC10 conversion input.

    #include "msp430x22x4.h"

    volatile unsigned int duty;
    int flag;
    int adcdata[3];


    void main(void)
    {
       WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      
       P2DIR |= 0x18;        //Setting P2.3 and P2.4 as outputs
       P2SEL |= 0x18;        //Selecting the special function of P2.3 and P2.4 for the PWM
      
       P4DIR |= 0x10;        //Setting P4.4 as output
       P4SEL |= 0x10;        //Selecting the special function of P4.4 for the PWM
      
       TACCR0 |= 1023;        //setting duty period of TimerA
       TBCCR0 |= 1023;        //setting duty period of TimerB
       TACCTL1 = OUTMOD_7;
       TACCTL2 = OUTMOD_7;    //OUTMOD_7: set until reaching TACCRx and reset after TACCRx until TACCR0
       TBCCTL1 = OUTMOD_7;
      
       ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON (stores it to ADC10MEM), interrupt enabled (ADC10IE), sample and hold time x16 (ADC10SHT)
      
       TACTL = TASSEL_2 + MC_1; 
       TBCTL = TBSSEL_2 + MC_1;
      
       flag = 0;
       for(;;){
        if(flag == 0){
            adcdata[0] = 0;
            ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE;
            ADC10CTL1 = INCH_0;                        
            ADC10CTL0 |= ENC + ADC10SC;
            adcdata[0] = ADC10MEM;
            TACCR1 = ADC10MEM;       
            ADC10CTL0 &= ~ENC;
            flag = 1;
        }
        if(flag == 1){
            adcdata[1] = 0;
            ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE;
            ADC10CTL1 = INCH_1;
            ADC10CTL0 |= ENC + ADC10SC;
            adcdata[1] = ADC10MEM;
            TACCR2 = ADC10MEM;
            ADC10CTL0 &= ~ENC;
            flag = 2;
        }
        if(flag == 2){
            adcdata[2] = 0;
            ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE;
            ADC10CTL1 = INCH_2;
            ADC10CTL0 |= ENC + ADC10SC;
            adcdata[2] = ADC10MEM;
            TBCCR1 = ADC10MEM;
            ADC10CTL0 &= ~ENC;
            flag = 0;
        }

       }
      
    }
       
    //I have tried to simplified it in many ways but always the PIN's got moved :S

    "

    PD: I know, that some variables I am not using them.

  • Hi,

    here is a short explainatiuon of what you need for DTC:

    1.) edit your linker control file or use lnk_msp430f2274_mod.cmd from my example
    You need to have a seperate segment in RAM which holds your ADC sample (the results were placed there by the DTC).
    Here's a brief into; have a look at the CCS manuals for details.
    1.1) define a custom segment in RAM, the name is ADCSAMPLE, it starts at 0x0200 (beginning of RAM) an it is 0x14 = 20bytes large

    MEMORY
    {
        SFR                     : origin = 0x0000, length = 0x0010
        PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
        PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100
        ADCSAMPLE    : origin = 0x0200, length = 0x0014
        RAM                     : origin = 0x0214, length = 0x03E8
    ..
    }

    1.2) define the new section

    SECTIONS
    {
        .bss       : {} > RAM                /* GLOBAL & STATIC VARS              */
        .sysmem    : {} > RAM                /* DYNAMIC MEMORY ALLOCATION AREA    */
        .stack     : {} > RAM (HIGH)         /* SOFTWARE SYSTEM STACK             */
        .adcsample : {} > ADCSAMPLE    /* RESERVED FOR SPECIAL VARIABLES    */
    ..
    }

    2.) add the code below to your example

    /*-----------------------------------------------------------------------------
    //   global variables stored in a seperate segment in RAM (ADCSAMPLE)
    //   contains the results of the ADC conversion  (ADRESULTS) and some special
    //   data (SPECIALS --> spare)
    //---------------------------------------------------------------------------*/
    #pragma DATA_SECTION (ADRESULTS, ".adcsample");
    #pragma DATA_ALIGN (ADRESULTS, 2);
    unsigned int ADRESULTS[8] = {0, 0, 0, 0, 0, 0, 0, 0};

    #pragma DATA_SECTION (SPECIAL, ".adcsample");
    #pragma DATA_ALIGN (SPECIAL, 2);
    unsigned int SPECIAL[2] = {0, 0};

    // flag variable for ADC control
    unsigned char bADC10FLAG = 0;


    /* ============================================================================
    //  Module name: void vadc10_isr(void)
    //
    //  Description:
    //               This module is the Interrupt service routine for the
    //               ADC10
    //                ADC10 - interrupt handler
    //                ADC10_VECTOR
    //
    //  Operation:
    //               samples R1 and R2 four times each and calculates the
    //               average value of the four samples
    // ==========================================================================*/
    #pragma vector=ADC10_VECTOR
    __interrupt void vadc10_isr(void)
    {
      ADC10CTL0 &= ~ADC10IFG;                 // clear interrupt flag, 0
      bADC10FLAG = 0x01;                      // set sample finished flag
    }

    /* ============================================================================
    //  Module name: void start_adconversion (void)
    //
    //  Description:
    //               This module starts an AD conversion
    //     sampled data is stored in a data buffer which starts at address
    //     0x0200
    //
    //  Operation: starts AD-conversion             
    // ==========================================================================*/
    void start_adconversion (void)

      ADC10CTL0 &= ~ENC;
      while (ADC10CTL0 & BUSY);
      ADC10SA = 0x0200;        // define data buffer start
      // start ADC10 conversion
      ADC10CTL0 |= ENC + ADC10SC;               // sampling and conversion start
    }

    /* ============================================================================
    //  Module name: vr2uppersamples (void)
    //
    //  Description:
    //              
    //  Operation:
    //               calculates the sum of 4 ADC-samples of R2 (connected to P2.1;
    //               ADRESULTS[1],ADRESULTS[3],ADRESULTS[5],ADRESULTS[7]) and
    //               divides the result by four (using shift instruction)
    //   averaged result is place in SPECIAL[0]
    // ==========================================================================*/
    void vr2uppersamples (void)
    {
     SPECIAL[0] = ADRESULTS[1] + ADRESULTS[3] + ADRESULTS[5] + ADRESULTS[7];
     SPECIAL[0] >>= 2;       // divide by four
    }

    /* ============================================================================
    //  Module name: vr1lowersamples (void)
    //
    //  Description:
    //              
    //  Operation:
    //               calculates the sum of 4 ADC-samples of R1 (connected to P2.0;
    //               ADRESULTS[0],ADRESULTS[2],ADRESULTS[4],ADRESULTS[6]) and
    //               divides the result by four (using shift instruction)
    //   averaged result is place in SPECIAL[1]
    // ==========================================================================*/
    void vr1lowersamples (void)
    {
     SPECIAL[1] = ADRESULTS[0] + ADRESULTS[2] + ADRESULTS[4] + ADRESULTS[6];
     SPECIAL[1] >>= 2;       // divide by four
    }


    // initialize ADC
    // P2.0 and P2.1 are used as analog inputs
    // P2.0 --> A0 --> samples R1
    // P2.1 --> A1 --> samples R2
    ADC10CTL1 = INCH_1 + CONSEQ_3;          // A1/A0, repeat multi channel
    ADC10CTL0 = ADC10SHT_1 + MSC + ADC10ON + ADC10IE;
    ADC10AE0 = 0x03;                        // P2.0, P2.1 ADC option selected
    ADC10DTC1 = 8;  // do 8 conversions in total

    // start the ADC by calling this function. It will sample each channel (A0 and A1) 4 times;
    start_adconversion();     // start ADC10

    // I'm now waiting for the AD conversion to be finished (polling my status flag)
    // you can do this in various ways (i.e. placing your code in the interrupt service routine ..) 
    while (!bADC10FLAG)
     __no_operation();      // wait for ad conversion to be finished
     bADC10FLAG = 0x00;      // reset flag variable for next turn

    // do the averaging
    //DTC will place the results in ADRESULTS like: AD0 1. sample, AD1 1. sample, AD0 2. sample, AD1 2. sample, ...
    // you can use the functions vr1lowersamples and vr2uppersamples for averaging the results (also gives you
    // more info on how DTC stores the results)
    vr2uppersamples();
    vr1lowersamples();

    Now take the averaged results in SPECIAL[] for your new duty cycles (CCRx values) like:
    TACCR1 = SPECUAL[0];
    TACCR2 = SPECIAL[1];

    Since you need a third channel you will have to enlager the segment ADCSAMPLE (don't forget to shrink RAM accordingly) and the variable ADRESULTS and SPECIALS.

    Hope this helps,
    rgds
    aBUGSworstnightmare

**Attention** This is a public forum