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.

PID controller in MSP430

Other Parts Discussed in Thread: MSP430G2553, MSP430G2231

I want to implement PID control algorithm in MSP430G2553. Please check whether I am correct.I am using a differential OP-AMP to subtract set-point and feedback signal externally to generate error signal. This error signal is sampled at 1KHz(Please also check whether my sampling frequency is 1KHz ).

#include "msp430g2231.h"
void main(void)
{
     WDTCTL = WDTPW + WDTHOLD;
     P1DIR=0xFF;
     unsigned int p=1,i=1,d=1,pp,pi,pd,error=0,past_error=0,sum=0,dt=1;

     ADC10CTL0 = SREF_0 | ADC10SHT_3 | ADC10ON ;
     ADC10CTL1 = INCH_1 | SHS_0 | ADC10DIV_0 | ADC10SSEL_0 | CONSEQ_0 ;  
     ADC10AE0 = BIT1 ;
     ADC10CTL0|=ENC;

     CCTL0 = CCIE;
     TACTL = TASSEL_2 + MC_1 + ID_3; //SMCLOCK(1MHz) is selected, UP-COUNTER,1MHz/8=125000Hz
     CCR0 = 125; // 125 corresponds to 1000 Hz

     while(1)
     {}
}

// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
    ADC10CTL0|=ADC10SC;

    while ( ADC10CTL1&ADC10BUSY);
    error=ADC10MEM;//Sampled at 1KHz

    pp=p*error;//Proportional controller
    sum=sum+error*dt;
    pi=sum*i;//Integral controller
    pd=(error-past_error)/dt;//Differential controller
    past_error=error;
    P1OUT=pp+pi+pd;//PID controller
}

  • Deepak murali said:
    Please check whether I am correct

    Who else if not you can possibly know whether your program does what is shall do? Run it, test it, and if it doesn't work and you cannot figure out, why then pos there what you tried and what you observed and where your observations differ from your expectations. This is a help and discussion forum, not a place for free software testing.

    However, you should get an instant compiler error about your variables. You declare pp, pi and sum as local variables for main and then you try to use them inside the ISR function. They should be global variables (declared outside main) to be visible to the ISR at all. And they should be declared as volatile.

    Then, what sense does it make to add their values and write the result to P1OUT?

    Also, it is abuse of interrupts to wait in the timer ISR for an ADC result.

    And your sampling frequency isn't 1kHz. Maybe somewhere near. If SMLCK were 1MHz, then CCR0=124 (and the divider of 8) would give 1kHz. But without any programming, the DCO frequency isn't 1MHz. It is typically 1.05MHz, but with a large tolerance. You need to load the calibration values for fairly well 1MHz system clock.

  • Hi Jens-Michael Gross,

                             Extremely sorry for not compiling the program before posting it on the forum. Any way thank you for your comments. Yeah I will replace the timer ISR with ADC thing.

  • Hi Jens-Michael Gross,

     Your reply : " And they should be declared as volatile."

    Can you please tell me why my variables must be volatile in the above case. The keyword 'Volatile' is used only when the microcontroller won't be able predict when the corresponding variable value will change. Ex: Microcontroller won't know when ADCMEM ,P1IN values will change(as they are given externally). So they will be declared as volatile inside the header file. But it is not so in the above case.

    And regarding ADC ISR, can you give me guidance about how to write program for a particular sampling frequency. I will make use of it. In the examples I saw I am unable to understand when the ADC ISR gets activated.   

  • Deepak murali said:
    Can you please tell me why my variables must be volatile in the above case.

    This is straight/default recommendation for beginners that uses global variables in the ISR - to avoid possible surprises if variable used elsewere in the code. If you are sure that those variables will be fine w/o volatile keyword - good!

    Maybe you can tell what you are doing here:

    Deepak murali said:
        P1OUT=pp+pi+pd;//PID controller

    You have 8-bit DAC connected to P1 output pins or what?

  • Hi Ilmars ,

                Yeah, I am using 8 bit DAC which will be connected to P1 port.  Is there any problem?

  • Deepak murali said:
    pp=p*error;//Proportional controller
        sum=sum+error*dt;
        pi=sum*i;//Integral controller
        pd=(error-past_error)/dt;//Differential controller
        past_error=error;
        P1OUT=pp+pi+pd;//PID controller

    Some minor hints and simple ideas that come up my mind to give some direction to you.

    All your variables are declared int so 16 bit long, your P1OUT is a 8 bit register, unless you really got your PI controll parameters under full control I would say that will lead to errors in the real execution.

    But as a start and for first prototyping and experiments this will actually fit, of course the real problems will come once you try to control some real physical values like current or voltage, so feel free to write about your following steps.

  • Deepak murali said:
    Can you please tell me why my variables must be volatile in the above case

    The compiler analyzes the program flow to detect redundant access of variables and other things. It re-organizes access and groups calculations to speed up program execution and lower code size. If, however, a variable is used inside an ISR as well as in main code, the program flow analysis cannot possibly know this (same for preemptive thread switching in a multitasking environment). The volatile keyword tells the compiler that the variable is special in a way outside the C language scope. As a result, each access to this variable is a break in the optimization. Number and order of accesses is untouched, and the surrounding code is split into before and after. This results in bigger and slower code, but ensures that the variable is immediately written to and no copy (e.g. in a register) is used, so ‘magic’ changes (due to hardware or ISR) are immediately recognized. All hardware registers are volatile.

    Btw: the volatile keyword might have no effect on local variables, as the compiler knows that there are no possible side-effects.

  • Hi Jens-Michael Gross,

         Thank you for your reply about volatile variables. But I am still using the same Timer ISR for ADC sampling. How do I use make my MSP430 to sample at a particular sampling rate without using timer interrupt? I checked my program(the program in which I used timer interrupt for sampling analog signal). It is working as expected. I mean, can you please guide  me more on this? 

     

    Jens-Michael Gross

             Also, it is abuse of interrupts to wait in the timer ISR for an ADC result.  

  • Deepak murali said:
    How do I use make my MSP430 to sample at a particular sampling rate without using timer interrupt?

    The PWM output signal of some timer CCR units can be used to directly trigger a conversion. It replaces the manual setting of the ADC12SC bit. See the ADC section of the users guide for the trigger mechanism and the timer section for the PWM functionality. Also, see the datasheet for which CCR unit output can be used as conversion trigger (this PWM signal is routed internally and not required to be present on an output pin, so you can still use the pins as GPIO)

    Regarding interrupts, ISRs are there to immediately react on an event. Waiting for an event inside an ISR is a death sin. In an ISR, do what needs to be done immediately (because timing-critical), for all other things, set a global flag or store the data in a global array and exit the ISR. Let the main code do it. A port pin ISR may start a timer delay and then exit. And the timer ISR then switches an I/O pin or sets a global flag, re-arms the port pin ISR and exits. (a typical pushbutton debounce construct). But waiting in the port pin ISR for the required delay is simply wrong. Not only because of definition, but also because an ISR cannot be interrupted by another interrupt (trying it anyway leads to all kind of hard to track problems and is also a sign of poor application design). Worst case is if you try to send a data package (e.g. a string) through a serial port, and the send function needs interrupts itself. This will cause an instant lockup.
    Simply put: if you need to ask why not, you should simply not do it. If you know when and how to do it safely, you don’t have to ask anymore and usually don’t need or want to do is anymore :)

**Attention** This is a public forum