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.

MSP430FR6989: PWM as DAC

Part Number: MSP430FR6989
Other Parts Discussed in Thread: MSP430G2231

Dear all,

I'm a new microcontroller programmer and I found it is so confusing to me to understand how the registers of the microcontroller work, and how to know which pin and PINSEL I have to chose when using timer A0, is there a table that shows the relations between pin's name and its functions, the user guide is confusing me, there are many tables with a lot of pins and numbers, so my first question is a detailed reference with examples to how to use this microcontroller, my second question is regarding my code, I want to read 9 analog values  through ADC then I saved it and mutilpied by other number ( for some reason) to use it as duty cycle of 9 PWM , the main goal of this code is to read an analog value, process it then convert it back to analog throgh PWM+ RC filter, I'm not sure what I'm doing is right I keep my code simple with only reading o ne value for testing purposes:

#include <msp430.h>
//#pragma PERSISTENT(FRAM_data)
//#include <msp430G2231.h>
#define ACLK 0x0100 // Timer ACLK source
#define UP 0x0010 // Timer UP mode
#define ENABLE_PINS 0xFFFE // Required to use inputs and outputs
#define ENABLE_PINS 0xFFFE // Enables inputs and outputs
//#define BIT2 0x0F
//volatile uint16_t ADCResults = 0;
void ADC_SETUP(void); // Used to setup ADC12 peripheral
const int x1=1;
const int x2=1;
volatile int multiplied_value;

main()
{
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
P1DIR =BIT0; // Set RED LED to output


ADC_SETUP(); // Sets up ADC peripheral
while(1)
{
ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Enable conversion
ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion
multiplied_value = (ADC12MEM0);
//P1OUT=multiplied_value;
if (multiplied_value > 0x800) // If input > 1.65V
{
P1OUT = BIT0; // Turn on red LED
}
else // Else input <= 1.65V
{
P1OUT = 0x00; // Turn off red LED
}


P1DIR |= BIT1; // P1.2 to output
P1SEL1 |= BIT1; // P1.2 to TA0.1
// P1SEL2 &= ~BIT6; // P1.7 to TA0.1

TA0CCR0 = multiplied_value; // PWM Period
TA0CCTL1 = OUTMOD_7; // CCR1 reset/set
TA0CCR1 = multiplied_value ; // CCR1 PWM duty cycle
TA0CTL = TASSEL_2 + MC_1; // SMCLK, up mode

_BIS_SR(LPM0_bits); // Enter LPM0
}
}
void ADC_SETUP(void)
{
#define ADC12_SHT_16 0x0200 // 16 clock cycles for sample and hold
#define ADC12_ON 0x0010 // Used to turn ADC12 peripheral on
#define ADC12_SHT_SRC_SEL 0x0200 // Selects source for sample & hold
#define ADC12_12BIT 0x0020 // Selects 12-bits of resolution
#define ADC12_P92 0x000A // Use input P9.2 for analog input
#define ADC12_P43 0x000A
#define ADC12_P32 0x000A
#define ADC12_P93 0x000A
#define ADC12_P14 0x000A
#define ADC12_P20 0x000A
#define ADC12_P41 0x000A
ADC12CTL0 = ADC12_SHT_16 | ADC12_ON ; // Turn on, set sample & hold time
ADC12CTL1 = ADC12_SHT_SRC_SEL; // Specify sample & hold clock source
ADC12CTL2 = ADC12_12BIT; // 12-bit conversion results
ADC12MCTL0 = ADC12_P92; // P9.2 is analog input
ADC12MCTL1 = ADC12_P43;
}

  • Hello Sali,

    I find the Input/Output Diagram Tables (Section 6.11.24 of the Datasheet) to be most helpful for understanding PxSEL pin settings. For example, the A10 functionality of P9.2 is selected with lines P9SEL1 |= BIT2; & P9SEL1 |= BIT2; and the TA0.1 PWM output is selected through P1SEL0 |= BIT66 & P1SEL1 |= BIT6 or P7SEL0 |= BIT2 or BIT6, depending on which pin you would like to use. If you want to use P1.2 then you should be configuring TA1, not TA0.

    No ADC12MCTLx registers should be set to the same ADC input channel and 0x200 of ADC12CTL1 changes the ADC12SHP (sample-and-hold pulse-mode select) bit, not the sample-and-hold source select (ADC12SHS) but this matters little since you are using the ADC12SC bit. You will need to evaluate the ADC12BUSY or ADC12IFG bits to make sure that a conversion is complete before storing the ADC12MEM0 value.

    Setting TA0CCR0 equal to TA0CCR1 will result in a 100% duty cycle at all times, TA0CCR1 should be a fraction of TA0CCR0. Timer initialization should exist outside of the while loop, where only TA0CCR1 is altered on every iteration. You also need to stop the watchdog timer at the beginning of you code. Please further evaluate the code examples provided by TI.

    Regards,
    Ryan
  • Thanks Ryan for your reply.

    Could please rewrite this section of your reply again, "No ADC12MCTLx registers should be set to the same ADC input channel and 0x200 of ADC12CTL1 changes the ADC12SHP (sample-and-hold pulse-mode select) bit, not the sample-and-hold source select (ADC12SHS) but this matters little since you are using the ADC12SC bit. You will need to evaluate the ADC12BUSY or ADC12IFG bits to make sure that a conversion is complete before storing the ADC12MEM0 value" 

    Really I did not fully understand it.

    Thank you so much,

    Sali

  • Sali,

    In the above code, ADC12MCTL0 = ADC12MCTL1 = 0x0A and this is not correct.

    The comment beside #define ADC12_SHT_SRC_SEL 0x0200 should change the source but it affects bit 9 instead, the ADC12SHP. But you use the ADC12SC as source anyways so ADC12SHSx remains zero as desired, perhaps you do intent to toggle ADC12SHP after all.

    You assign a variable to ADC12MEM0 right after starting a conversion using the ADC12SC bit without allowing any time for the conversion to complete, therefore the value in ADC12MEM0 is not current when assigned.

    Regards,
    Ryan
  • Thanks for the reply.

    so you said "ADC12MCTL0 = ADC12MCTL1 = 0x0A and this is not correct". as of my understanding you meant 

    ADC12MCTL0 = ADC12_P92; // P9.2 is analog input
    ADC12MCTL1 = ADC12_P43;

    So how to read more than one analog signal at the same time. I have 9 to 10 analog inputs

    Thank you

  • you mean I should assign different addresses here:
    #define ADC12_P92 0x000A // Use input P9.2 for analog input
    #define ADC12_P43 0x000A
    #define ADC12_P32 0x000A
    #define ADC12_P93 0x000A
    #define ADC12_P14 0x000A
    #define ADC12_P20 0x000A
    #define ADC12_P41 0x000A
  • That is correct Sali, ADC12_Pxx should have different values corresponding to various analog input pins.

    Regards,
    Ryan
  • Thanks Ryan.
    now my code is:

    #include <msp430.h>
    #define ACLK 0x0100 // Timer ACLK source
    #define UP 0x0010 // Timer UP mode
    #define ENABLE_PINS 0xFFFE // Required to use inputs and outputs
    #define ENABLE_PINS 0xFFFE // Enables inputs and outputs
    void ADC_SETUP(void); // Used to setup ADC12 peripheral
    const int x1=1;
    const int x2=1;
    volatile int multiplied_value;

    main()
    {
    PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
    P1DIR =BIT0; // Set RED LED to output


    ADC_SETUP(); // Sets up ADC peripheral
    while(1)
    {
    ADC12CTL0 = ADC12CTL0 | ADC12ENC; // Enable conversion
    ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion
    while ( ADC12BUSY == 1){
    multiplied_value = (ADC12MEM0);
    if (multiplied_value > 0x800) // If input > 1.65V
    {
    P1OUT = BIT0; // Turn on red LED
    }
    else // Else input <= 1.65V
    {
    P1OUT = 0x00; // Turn off red LED
    }


    P2DIR |= BIT1; // P2.1 to output
    P2SEL1 |= BIT1; // P2.1 to TA0.1

    TA0CCR0 = multiplied_value*2; // PWM Period
    TA0CCTL1 = OUTMOD_7; // CCR1 reset/set
    TA0CCR1 = multiplied_value ; // CCR1 PWM duty cycle
    TA0CTL = TASSEL_2 + MC_1; // SMCLK, up mode

    _BIS_SR(LPM0_bits); // Enter LPM0
    }
    }
    }
    void ADC_SETUP(void)
    {
    #define ADC12_SHT_16 0x0200 // 16 clock cycles for sample and hold
    #define ADC12_ON 0x0010 // Used to turn ADC12 peripheral on
    #define ADC12_SHT_SRC_SEL 0x0200 // Selects source for sample & hold
    #define ADC12_12BIT 0x0020 // Selects 12-bits of resolution
    #define ADC12_P92 0x000A // Use input P9.2 for analog input
    //#define ADC12_P43 0x000A
    //#define ADC12_P32 0x000A
    //#define ADC12_P93 0x000A
    //#define ADC12_P14 0x000A
    //#define ADC12_P20 0x000A
    //#define ADC12_P41 0x000A
    ADC12CTL0 = ADC12_SHT_16 | ADC12_ON ; // Turn on, set sample & hold time
    ADC12CTL1 = ADC12_SHT_SRC_SEL; // Specify sample & hold clock source
    ADC12CTL2 = ADC12_12BIT; // 12-bit conversion results
    ADC12MCTL0 = ADC12_P92; // P9.2 is analog input
    //ADC12MCTL1 = ADC12_P43;
    }



    I measured pin P9.2 , it is 2 volts and I want to produce PWM, I assigned the period as 4 and the duty cycle as 2 so I expect the frequency at pin p2.1 to be 0.25 Hz but it is 0.5 KHz ! I do not know why it gives me this number.
  • What is the AVCC reference supply voltage, ADC12MEM0, and multiplied_value? If the TA0CCR0 really is 4 then the output frequency should be ~250 kHz since SMCLK is 1.048 MHz (default).

    Regards,
    Ryan
  • Hi Ryan,

    Thank you for your patience with me I know I might ask some silly questions but this is totally new stuff for me, I never used msp430 .

    I'm connecting the the chip to the pc through USB so I assume the reverence voltage is 3.3 V.

    Then I created a small test circuit to ensure that the MCU works probably, my circuit is just a potentiometer that is connected directly to the  MCU, the output of the potentiometer is connected to the pin 9.2 (analog input) I adjust the potentiometer to give an output voltage of 2 V then I save this value in "multiplied_value" variable.

    Now the period of the PWM = multiplied_value*2.

    duty cycle=multiplied_value

    ADC12MEM0, as of my understanding when I use ADC12CTL0 to enable and start conversion the converted analog value will be automatically saved in ADC12MEM0!, am I right?

    Thank you,

    Sali

  • With an input of 2 V with a 3.3 V reference and 12-bit (4096 points) resolution:

    multiplied_value = ADC12MEM0 = (2/3.3)*4096 = 2482

    TACCR0 = 2482*2 = 4965

    So in timer up mode with a default SMCLK source I expect a period of 1048576/4965 = 211 Hz, you will have to debug your program to figure out the disparity.

    Regards,
    Ryan
  • Hi Ryan

    What is 1048576? 

    Shall I put sample and hold rate = SMCLK?

  • 2^20 = 1048576 = default SMCLK frequency, at this point we have just been discussing it for timer purposes. Your ADC sample-and-hold-time is set on the number of ADCCLK cycles, the code provided indicates 16 ADC12OSC (MODOSC, 4.8 MHz) cycles. I don't understand your association between ADC sampling and SMCLK.

    Regards,
    Ryan
  • SMCLK is 16Mhz or 2.048 MHz or 2 ^20 ? I found different numbers in the online documents!

  • The maximum SMCLK is 16 MHz but it is not the default. The start-up settings are DCOFSEL = 6 (8 MHz) and DIVS/DIVM = 3 (/8) for 1 MHz.

    Regards,
    Ryan

**Attention** This is a public forum