1 PULSE PER SECOND USING MSP430 WITH AN EXTERNAL OSCILLATOR

Thread Starter

Omer Dagan

Joined Dec 4, 2016
23
Hello ,

I'm using MSP430F5131 and attached an external crystal of 12.8MHz to
pins PJ.4 and PJ.5 .

I would like to generate a 1 pulse per second using this external clock
while the output of the 1pps should be P2.4 , im also using Timer D
(TD0.0) .


Could you help me writing the code (I'm using Code Composer Studio)
about how to generate that 1 pps using the external crystal and Timer D
(TD0.0) and how to define the timer d and the external crystal.

thanks in advance.
 

Thread Starter

Omer Dagan

Joined Dec 4, 2016
23
thanks for the reply ,
I have written this code for the 1pps (along with some conditions) .
could you please check this code and give me some notes about it?

thanks in advance.

Code:
#include <msp430.h>
#include <intrinsics.h>



unsigned int timerCount = 0;
int main(void) {


    WDTCTL = WDTPW | WDTHOLD;                    // Stop watchdog timer
    P2OUT &= ~(BIT4);                             //preload 1pps to '0'


    // set I/O pins directions
    P1DIR |=BIT6+BIT7;                      //set p1.x to 11000000
    P2DIR |=BIT4;                           // Set P2.4 to output direction
    PJDIR |=BIT0+BIT1+BIT3;                // set pj.x output 0000 1011
    P2SEL |= BIT4;                            //select the option of using TD0.0 in pin 2.4
    P2IES |= BIT4;                        // high -> low is selected with IES.x = 1.
    P2IFG &= ~BIT4;                          // To prevent an immediate interrupt, clear the flag for
                                          // P1.3 before enabling the interrupt.
    P2IE |= BIT4;                          // Enable interrupts for P1.3

    // Configure XT1 (external oscillator)
    PJSEL |= BIT4+BIT5;                        // port select for xt1
    UCSCTL6 &= ~(XT1OFF);                     //xt1 is on
    UCSCTL3 = 0;                            // FLL REFERENCE CLOCK REFERENCE = XT1

    // configure TD0.0 to output of 1 pulse per second

    TD0CCR0=16000-1;                          // setting TAR count up value 16000 (12.8MHz / 8 = 1.6MHz , 1.6MHz / 100 = 16000 Hz) when 100 is passed means 1 second has passed as well
    //TD0CCR1=                                 //DUTY CYCLE OF 50%
    //TD0CCTL1=CCIE + OUTMOD_7;                    //enabling interuption + RESET/SET OUTPUT MODE
    TD0CTL0 =MC_2+ID_3+TDSSEL_0+TAIE;                //defining timer d TD0.0 (P2.4)

    __enable_interrupt();


    for(;;){                      // main loop (looping forever)



        //   EXTERNAL / INTERNAL SELECTION BY SW4

        if ((P2IN & BIT2)==0){         //  INTERNAL MODE
            PJOUT |=BIT3;              // sends '1' from pj.3 output to the multiplexer U4 (uses the internal 1pps)

            //PULSE 1 : DESCRETE ON/OFF AND SWITCH ON/BAD/OFF

                     if ((P2IN & BIT0)==0 || (P1IN & BIT0)==0) {        //NORMAL SIGNAL OF 1PPS checks if descrete source is on or 1pps sw pulse 1 is on
                         P1OUT |= BIT6;                                     //ENABLES PULSE BY THE 'AND' GATE
                         PJOUT |= BIT0;                                    //ENABLES TTL TO RS232 CONVERTER (FOR DIFF OUTPUT)
                        #pragma vector = TIMER0_D0_VECTOR
                         __interrupt void TIMER0_D0(void){
                       if (++timerCount > 50) {                           // checks if the incrementation of timerCount reaches 50 (means 0.5 second has passed)
                                           P2OUT ^=BIT4;               //generates 1pps out of p2.4
                                           timerCount = 0;             // resets the timer count
                                           }
                                           P2IFG &=˜BIT4;             // clears the fl
                         }

                     }
                   }
                     else {
                         P1OUT |= ~BIT6;                                 //DISABLES PULSE BY SENDING A '0' TO THE AND GATE
                     }

                     if ((P1IN & BIT2)==0)  {                            //PULSE 1 BAD SIGNAL ???
                         // CODE HERE FOR BAD SIGNAL PULSE 1//
                     }

                     //PULSE 2 : DESCRETE ON/OFF AND SWITCH ON/BAD/OFF


                     if ((P2IN & BIT1)==0 || (P1IN & BIT0)==0){            //NORMAL SIGNAL OF 1PPS checks if descrete source is on or 1pps sw pulse 2 is on
                         P1OUT |= BIT7;                                     //ENABLES PULSE BY THE 'AND' GATE
                         PJOUT |= BIT1;                                     //ENABLES TTL TO RS232 CONVERTER (FOR DIFF OUTPUT)
                    #pragma vector = TIMER0_D0_VECTOR                 //GENERATES 1PPS EVERY 1s
                   __interrupt void TIMER0_D0 (void){
                       if (++timerCount > 50) {                           // checks if the incrementation of timerCount reaches 100 (means 1 second has passed)
                                             P2OUT ^=BIT4;               //generates 1pps out of p2.4
                                             timerCount = 0;             // resets the timer count
                                             }
                                             P2IFG &= ˜BIT4;             // clears the fl
                     }


        }
                     else {
                         P1OUT |= ~BIT7;                                    //DISABLES PULSE BY SENDING A '0' TO THE AND GATE
                     }

                     if ((P1IN & BIT3)==0){                                //PULSE 1 BAD SIGNAL ???
                         // CODE HERE FOR BAD SIGNAL PULSE 1//
                     }


                     }

        else {                                                                //EXTERNAL MODE
            PJOUT |= ~BIT3;            //sends '0' from pj.3 output to the multimplexer U4 (uses the external 1pps)
            P1OUT |= BIT6;                  // ENABLES PULSE 1
            P1OUT |= BIT7;                //ENABLES PULSE 2
            PJOUT |= BIT0;                //ENABLES RS422 DIFF OUTPUT    FOR PULSE 1
            PJOUT |= BIT1;                // ENABLES RS422 DIFF OUTPUT FOR PULSE 2
                }
        }
}


    return 0;
 

MrChips

Joined Oct 2, 2009
30,701
Does the code work?
What does it do?
Do you have access to an oscilloscope?

I would break down your task into simpler steps. Test one thing at a time.
  1. Set up a timer module interrupt for any period.
  2. Test that it is working.
I can take a look at this but not for the next three days.

Take a look at my MSP430 blog.
 

Thread Starter

Omer Dagan

Joined Dec 4, 2016
23
Hello ,
First of all thank you for the quick reply.

I will explain a little about the project :
My main goal is to generate a 1 pulse per second using a duty cycle of 50% by a 12.8MHz external oscillator.
I already have a printed PCB for that project which means i got to understand what the previous designer had done and implement it into my CCS program in order to program my micro controller.
i am still new to this whole microcontroller world and im eager to know more , although im short in time.

I have attached an electrical wiring of the PCB to help you understand a little bit more about the project.

A little explanation of the electrical wiring:
An external toggle switch (from connector J6 "Internal/External Selection") switch between an external 1pps (From an external GPS) or internal 1pps (by the msp430).
if we choose an internal mode then (input P2.2) a '1' (or '0' if its an active low mode which is an active low mode) sends from PJ.3 (ouput) to U4 and a 1 pulse per second gets out of P2.4 output to connectors J8 and J9 (same pulse different connectors).

I can Switch signals to ON/BAD/OFF by using an external toggle switch(pins 1,2 of J3 connector) or a descrete (pin 3 of J3 connector).
if i toggle the switch to on mode it sends '1'(or '0' if its an active low mode which is an active low mode) through P1.6 to U5 ( And Gate) and enables the pulse it also sends '1' through PJ.0 to U6 and converts the pulse from TTL to RS422 (differetial).
The descrete switching option switches the pulse (ON/OFF) the same as the external toggle switch.
This is refers to PULSE 1 , i need to implement the same thing for PULSE 2.

although im still not sure what RST/NMI/SBWTDIO and TEST/SBWTCK are wired for , are these for downloading the program into the msp?
im also not sure about the PJ.2 pin (FUNCTIONALITY DISABLE).

I know its a lot to read but im really short in time about this project and i dont have much time to study everything.
so i would be very glad if you could read the code and help me implement the functions into the code.

thanks in advance.
 

Attachments

Kermit2

Joined Feb 5, 2010
4,162
The pulse is seldom more than 1 millisecond duration and more often is in the microsecond range.

50% duty cycle would mean 500 milliseconds duration.
 

dannyf

Joined Sep 13, 2015
2,197
To help you get start, here is a piece of sample code that produces a 2pps pulse train.

Code:
//#include <msp430.h>                     //we use ccs/msp430
#include <msp430.h>                        //we use iar msp430
#include "gpio.h"                        //we use gpio
#include "delay.h"                        //we use software delays
#include "tmra0.h"                        //timer a

//hardware configuration
#define _1PPS_PORT        P3OUT
#define _1PPS_DDR        P3DIR
#define _1PPS_PIN        (1<<0)
#define _1PPS_CNT        50                //count for overflow -> 50*10000us = 500ms -> 2pps
#define _1PPS_PR        10000            //1pps period, 1us
#define _1PPS_DC()        {NOP4();}        //1pps duration
//end hardware configuration

//global defines

//global variables

//output routine
void _1pps_out(void) {
      static uint16_t cnt=_1PPS_CNT;        //counter internal to the o utput routine
   
    cnt--;
    if(cnt==0) {                        //roll-over
        cnt = _1PPS_CNT;                //reload
        IO_SET(_1PPS_PORT, _1PPS_PIN);    //set the pin
        _1PPS_DC();                        //waste some time
        IO_CLR(_1PPS_PORT, _1PPS_PIN);    //clera the pin
    }
}

int main(void) {

    mcu_init();                            //reset the mcu
    //GIO_OUT(LED1_GPIO, LED1);            //set led as output

    //set up the output pin
    IO_CLR(_1PPS_PORT, _1PPS_PIN);        //1pps idles low
    IO_OUT(_1PPS_DDR, _1PPS_PIN);        //1pps as output pin
   
    //set up the timer
    tmra0_init(TMRA_PS1x);                //prescaler = 1:1
    tmra0_setpr1(_1PPS_PR);                //set up the period
    tmra0_act1(_1pps_out);                //install user handler
    ei();                                //enable interrupt

    while (1) {
    };
   
    return 0;
}
The code in action:
msp430_2pps.PNG

The basic principle is outlined earlier. The basic logic follows if you are to port the code to different targets. To reconfig it for 1pps, you just need to change _1PPS_CNT / _1PPS_PR.
 

Thread Starter

Omer Dagan

Joined Dec 4, 2016
23
Thank you , although im not familiar with the those libraries :
  1. #include "gpio.h" //we use gpio
  2. #include "delay.h" //we use software delays
  3. #include "tmra0.h" //timer a
there are some function i havnt heard of before .
could i get some explanation about that code?
Where can i get that code analysis program from?
thanks.
 

Thread Starter

Omer Dagan

Joined Dec 4, 2016
23
when i have multiple conditions in my main function , (such as : if ((P2IN & BIT2)==0)
and i want to generate the 1pps when this condition becomes true and stops it when its false , although the ISR function cannot be placed in the main function - it's supposed to be outside the function , so how can i make that connection between the ISR function and the condition ? and how can i do that when i have multiple conditions?
 
Last edited:

dannyf

Joined Sep 13, 2015
2,197
Here is an example - it is an actual project of mine. A high stability tcxo (TCO-919) drives a 12F675 to generate 1pps, inhabitable by a user pin (active low).

12f675_1pps.PNG

The trick is to design the system so that the output is jitter-free with regards to the user input (GP0 in this case).

Shown here is a case where GP0 is driven by a 0.3Hz input signal. When GP0 is pulled low, the output is disabled (stays high). When GP0 is pulled high or left floating, the output is enabled.
 

dannyf

Joined Sep 13, 2015
2,197
it was pointed out to me, quite correctly, that rather than paralleling GP1/2, it is much more useful to make one of them non-inhabitable and the other user-inhabitable.

Thus the following revision:

12f675_1ppsv2.PNG
 

Thread Starter

Omer Dagan

Joined Dec 4, 2016
23
Alright i understand thank you .
i have implemented these in my code .
succeded to make that connection between the ISR to my 1PPS output's conditions.
i have compiled the code and no errors have been found .
now i would like to simulate the code in the IAR Embedded Workbench - want to see the 1pps output in the timeline.
i think i might need to force the imputs. how do i do that?
 

Thread Starter

Omer Dagan

Joined Dec 4, 2016
23
Code:
#include "msp430.h"
#include "intrinsics.h"

// defining flags as volatile(coz we use these variables in the main and in the ISR as well):
volatile unsigned int timerCount = 0;     //defines the millisecond counter
volatile unsigned int normalPulse1=0;     //defines another flag to indicates when 1 second has passed for normal pulse1
volatile unsigned int badPulse1=0;        //defines another flag to indicates when 1 second has passed for bad pulse1
volatile unsigned int normalPulse2=0;     //defines another flag to indicates when 1 second has passed for normal pulse2
volatile unsigned int badPulse2=0;        //defines another flag to indicates when 1 second has passed for bad pulse2
volatile unsigned int secondsCount=0;    //defines the seconds count for the bad pulse


void main() { //Main function

    // configure watchdog timer:
    WDTCTL = WDTPW | WDTHOLD;                    // Stop watchdog timer
    P2OUT &= ~(BIT4);                             //preload 1pps to '0'


    // set I/O pins directions:
    P1DIR |=BIT6+BIT7;                      //set p1.x to 11000000
    P2DIR |=BIT4;                           // Set P2.4 to output direction
    PJDIR |=BIT0+BIT1+BIT3;                // set pj.x output 0000 1011
    P2SEL |= BIT4;                           //select the option of using TD0.0 in pin 2.4
    //P2IES |= BIT4;                         // high -> low is selected with IES.x = 1.
    //P2IFG &= ~(BIT4);                      // To prevent an immediate interrupt, clear the flag for
                                          // P2.4 before enabling the interrupt.
    //P2IE |= BIT4;                          // Enable interrupts for P2.4

    // Configure XT1 (external oscillator):
    PJSEL |= BIT4+BIT5;                        // port select for xt1
    UCSCTL6 &= ~(XT1OFF);                     //xt1 is on
    UCSCTL3 = 0;                            // FLL REFERENCE CLOCK REFERENCE = XT1

    // configure TD0.0 (TimerD0.0):
    TD0CTL0 |=MC_1+ID_3+TDSSEL_0+TDIE+CNTL_0+TDCLR;                //defining timer d TD0.0 (P2.4) upmode , devide by 8 , TDCLK , enable interupt ,
    TD0CCR0=1600-1;                          // setting TAR count up value 1600 (12.8MHz / 8 = 1.6MHz , 1.6MHz / 1600 = 1000 Hz) when 1000 is passed means 1 second has passed as well

    TD0CCTL0 |= CCIE;                        //ENABLES CCIFG INTERUPT ON CCR0
   

    __enable_interrupt();                        //enables interupts in the ISR


    for(;;){                      // Main loop - Endless loop



        //   EXTERNAL / INTERNAL SELECTION BY SW4

        if ((P2IN & BIT2)==0){         //  INTERNAL MODE
       
            PJOUT |=BIT3;              // sends '1' from pj.3 output to the multiplexer U4 (uses the internal 1pps)

            //PULSE 1 : DESCRETE ON/OFF AND SWITCH ON/BAD/OFF

                     if ((P2IN & BIT0)==0 || (P1IN & BIT0)==0) {        //NORMAL SIGNAL OF 1PPS checks if descrete source is on or 1pps sw pulse 1 is on
                         P1OUT |= BIT6;                                     //ENABLES PULSE BY THE 'AND' GATE
                         PJOUT |= BIT0;                                    //ENABLES TTL TO RS232 CONVERTER (FOR DIFF OUTPUT)
                          if(normalPulse1==1){                       //checks if normalPulse1 is on from the ISR
                            normalPulse1 =0;                           // sets normalPulse1 to 0 again so the ISR will generate the pulse
                            P2OUT ^=BIT4;                            //generates 1pps out of p2.4
                         }

                     }
                  
                     else {
                         P1OUT |= ~(BIT6);                                 //DISABLES PULSE BY SENDING A '0' TO THE AND GATE
                     }

                     if ((P1IN & BIT2)==0)  {                            //PULSE 1 BAD SIGNAL checks if the 1pps sw bad pulse is on
                          P1OUT |= BIT6;                                     //ENABLES PULSE BY THE 'AND' GATE
                          PJOUT |= BIT0;                                    //ENABLES TTL TO RS232 CONVERTER (FOR DIFF OUTPUT)
                            if(badPulse1==1){                             //checks if badPulse1 is on from the ISR
                              badPulse1=0;                                // sets badPulse1 to 0 again so the ISR will generate the pulse
                              P2OUT ^=BIT4;                            //generates 1pps out of p2.4
                           
                            }
                     }

                     //PULSE 2 : DESCRETE ON/OFF AND SWITCH ON/BAD/OFF


                     if ((P2IN & BIT1)==0 || (P1IN & BIT0)==0){            //NORMAL SIGNAL OF 1PPS checks if descrete source is on or 1pps sw pulse 2 is on
                         P1OUT |= BIT7;                                     //ENABLES PULSE BY THE 'AND' GATE
                         PJOUT |= BIT1;                                     //ENABLES TTL TO RS232 CONVERTER (FOR DIFF OUTPUT)
                            if(normalPulse2==1){
                                normalPulse2=0;                                // sets normalPulse2 to 0 again so the ISR will generate the pulse
                                P2OUT ^=BIT4;                            //generates 1pps out of p2.4
                           
                            }


                     }


       
                     else {
                         P1OUT |= ~(BIT7);                                    //DISABLES PULSE BY SENDING A '0' TO THE AND GATE
                     }

                     if ((P1IN & BIT3)==0){                                //PULSE 2 BAD SIGNAL
                          P1OUT |= BIT6;                                     //ENABLES PULSE BY THE 'AND' GATE
                          PJOUT |= BIT0;                                    //ENABLES TTL TO RS232 CONVERTER (FOR DIFF OUTPUT)
                            if(badPulse2==1){
                                badPulse2=0;                                // sets badPulse2 to 0 again so the ISR will generate the pulse
                                P2OUT ^=BIT4;                            //generates 1pps out of p2.4
                            }
                     }


                     }

        else {                                                                //EXTERNAL MODE
            PJOUT |= ~(BIT3);            //sends '0' from pj.3 output to the multiplexer U4 (uses the external 1pps)
            P1OUT |= BIT6;                  // ENABLES PULSE 1
            P1OUT |= BIT7;                //ENABLES PULSE 2
            PJOUT |= BIT0;                //ENABLES RS422 DIFF OUTPUT    FOR PULSE 1
            PJOUT |= BIT1;                // ENABLES RS422 DIFF OUTPUT FOR PULSE 2
                }
        }
       
}

   
   
                    //ISR FOR TIMERD0.0 - NORMAL/BAD PULSE 1 AND 2
                   
                   
                   
                    #pragma vector = TIMER0_D0_VECTOR                 //GENERATES 1PPS EVERY 1s for normal pulse
                   __interrupt void TIMER0_D0 (void){
                      
                       //NORMAL PULSE 1 AND 2:
                      
                       if (++timerCount > 500) {                           // checks if the incrementation of timerCount reaches 500 (means 1 second has passed)toggling means doubling the time this is why we need to devide the time to a half. (1000/2=500)
                                          timerCount = 0;             // resets the millisecond counter to 0
                                   normalPulse1 = 1;             //once it reaches 500 (1 second) normalPulse1 will be 1
                                   normalPulse2 = 1;                //once it reaches 500 (1 second) normalPulse2 will be 1
                                 secondsCount++;
                                             }
                                           
                    
                    // BAD PULSE 1 AND 2:
                   
               
                       if (secondsCount == 2) {                           // checks if the incrementation of secondCount reaches 2 seconds for bad pulse (means 2 second has passed)
                                    secondsCount = 0;             // resets the millisecond counter to 0
                                    badPulse1=1;                    // once it reaches 2000( 2 seconds) the badPulse1 will be 1.
                                    badPulse2=1;                    // once it reaches 2000( 2 seconds) the badPulse2 will be 1.
                                             }
                                            
}
Thanks in advanced.

Moderator edit: added code tags.
 

Thread Starter

Omer Dagan

Joined Dec 4, 2016
23
I'm using IAR embedded workbench and compiled my code without any errors , although when i click on download and debug button i get this error (in red):
 
Top