drankinatty

MSP432 PWM Control of Tri-Color LED

Sep 18th, 2021
863
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /******************************************************************************
  2.  * MSP432 PWM control of tri-color LED
  3.  *
  4.  * Description: DriverLib example using PWM to control color and brightness
  5.  *              of tri-color LED. LED1 reflects the current duty cycle change
  6.  *              rate. sw1 turns the LED1 blink on/off. The PWM duty cycle controls
  7.  *              the brightness of the tri-color LED (LED2). Color change occurs each
  8.  *              complete cycle through the PWM duty cycles (brightness) of each color
  9.  *              on LED2.
  10.  *
  11.  *                MSP432P401
  12.  *             ------------------
  13.  *            |                  |
  14.  *            |                  |  Duty Cycle - press to select
  15.  * P1.0 LED --|sw1            sw2|-- 1 sec (default), 1/2 sec., 1/4 sec., 1/8 sec.,
  16.  * blink      |                  |   1/16 sec 1/32 sec., 1/42 sec., 1/56 sec.
  17.  * on/off     |                  |
  18.  *            |                  |   (returns from 1/56 back to 1 on next press)
  19.  *            |                  |
  20.  *            |                  |
  21.  * Author: David C. Rankin
  22. *******************************************************************************/
  23. /* DriverLib Includes */
  24. #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
  25.  
  26. /* Standard Includes */
  27. #include <stdint.h>
  28. #include <stdbool.h>
  29.  
  30. #define PWM_CCR0          127
  31. #define PWM_CCR0_MIN       20
  32. #define PWM_CCR0_STEP       1
  33. #define TA1_CCR0        46875
  34.  
  35. static volatile bool toggle;                        /* toggle P1.0 LED (false - off) */
  36. static volatile bool dirUp;                         /* dir flag for RGB LED PWM step */
  37. static volatile uint8_t color;                      /* RGB LED color (R or G or B) */
  38. static volatile int16_t ta0_ccr1;                   /* Timer_A0 CCR1-3 value */
  39. static volatile uint_fast16_t ta1_ccr0;             /* Timer_A1 CCR0 value */
  40.  
  41. /* TimerA0 UpMode Configuration Parameter for PWM */
  42. const Timer_A_UpModeConfig upConfigTA0 =
  43. {
  44.     TIMER_A_CLOCKSOURCE_SMCLK,                      /* SMCLK Clock Source */
  45.     TIMER_A_CLOCKSOURCE_DIVIDER_1,                  /* SMCLK/1 = 3MHz */
  46.     PWM_CCR0,                                       /* 128 clock cycles */
  47.     TIMER_A_TAIE_INTERRUPT_DISABLE,                 /* Disable Timer interrupt */
  48.     TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE,            /* Disable CCR0 interrupt */
  49.     TIMER_A_DO_CLEAR                                /* Clear divider, direction, count */
  50. };
  51.  
  52. /* Timer_A0 CCR1 compare configuration parameters
  53.  * NOTE: CCR0 only supports the following output modes
  54.  *   TIMER_A_OUTPUTMODE_OUTBITVALUE
  55.  *   TIMER_A_OUTPUTMODE_SET
  56.  *   TIMER_A_OUTPUTMODE_TOGGLE
  57.  *   TIMER_A_OUTPUTMODE_RESET
  58.  * that is why you use CCR1 - CCR3 for the compare registers
  59.  * with TIMER_A_OUTPUTMODE_TOGGLE_RESET
  60.  * (while you can force CCR0 to take TOGGLE_RESET - it is Undefined Behavior)
  61.  * See Tech Reference 19.2.5.1 pg 791.
  62.  * Toggle_Reset starts duty-cycle at CCR1-3 and stops when CCR0 roll-over occurs.
  63.  */
  64. Timer_A_CompareModeConfig compareConfigA01 =
  65. {
  66.      TIMER_A_CAPTURECOMPARE_REGISTER_1,             /* Use CCR1 as compare register */
  67.      TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,      /* Disable CCR interrupt */
  68.      TIMER_A_OUTPUTMODE_TOGGLE_RESET,               /* Toggle-reset output mode */
  69.      125                                            /* Compare value (CCR1) Dim */
  70. };
  71.  
  72. /* Timer_A0 CCR2 compare configuration parameters */
  73. Timer_A_CompareModeConfig compareConfigA02 =
  74. {
  75.      TIMER_A_CAPTURECOMPARE_REGISTER_2,             /* Use CCR2 as compare register */
  76.      TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,      /* Disable CCR interrupt */
  77.      TIMER_A_OUTPUTMODE_TOGGLE_RESET,               /* Toggle-reset output mode */
  78.      0                                              /* Compare value (CCR2) off */
  79. };
  80.  
  81. /* Timer_A0 CCR3 compare configuration parameters */
  82. Timer_A_CompareModeConfig compareConfigA03 =
  83. {
  84.      TIMER_A_CAPTURECOMPARE_REGISTER_3,             /* Use CCR3 as compare register */
  85.      TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,      /* Disable CCR interrupt */
  86.      TIMER_A_OUTPUTMODE_TOGGLE_RESET,               /* Toggle-reset output mode */
  87.      0                                              /* Compare value (CCR3) off */
  88. };
  89.  
  90. /* TimerA1 UpMode Configuration Parameter for Interrupt where PWM/color is changed */
  91. const Timer_A_UpModeConfig upConfigTA1 =
  92. {
  93.     TIMER_A_CLOCKSOURCE_SMCLK,                      /* SMCLK Clock Source */
  94.     TIMER_A_CLOCKSOURCE_DIVIDER_64,                 /* SMCLK/64 = 48.875KHz */
  95.     TA1_CCR0,                                       /* ~1/sec on/off */
  96.     TIMER_A_TAIE_INTERRUPT_DISABLE,                 /* Disable Timer interrupt */
  97.     TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE,             /* Enable CCR0 interrupt */
  98.     TIMER_A_DO_CLEAR                                /* Clear divider, direction, count */
  99. };
  100.  
  101. /* Port mapper configuration register (See Table 13-1 Tech Reference, Pg 702)
  102.  * Timer_A0 CCR1-3 are mapped to take the PWM output for the RGB LED.
  103.  */
  104. const uint8_t port_mapping[] =
  105. {
  106.   PM_TA0CCR1A, PM_TA0CCR2A, PM_TA0CCR3A, PM_NONE, PM_NONE, PM_NONE, PM_NONE, PM_NONE
  107. };
  108.  
  109. int main(void)
  110. {
  111.     toggle = true;
  112.     dirUp = false;
  113.     color = 1;
  114.     ta0_ccr1 = PWM_CCR0;
  115.     ta1_ccr0 = TA1_CCR0;
  116.  
  117.     /* Stop Watchdog  */
  118.     MAP_WDT_A_holdTimer();
  119.  
  120.     /* Configuring P1.0 as output */
  121.     MAP_GPIO_setAsOutputPin (GPIO_PORT_P1, GPIO_PIN0);
  122.     MAP_GPIO_setOutputLowOnPin (GPIO_PORT_P1, GPIO_PIN0);
  123.  
  124.     /* Confinguring P1.1 & P1.4 as an input and enabling interrupts */
  125.     MAP_GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
  126.     MAP_GPIO_clearInterruptFlag (GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
  127.     MAP_GPIO_enableInterrupt (GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
  128.     MAP_GPIO_interruptEdgeSelect (GPIO_PORT_P1, GPIO_PIN1 |
  129.                                     GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);
  130.  
  131.     /* Initialize main clock to 3MHz */
  132.     MAP_CS_setDCOCenteredFrequency (CS_DCO_FREQUENCY_3);
  133.  
  134.     /* Configuring TimerA1 for Up Mode to generate an interrupt on CCR0 roll-over */
  135.     MAP_Timer_A_configureUpMode (TIMER_A1_BASE, &upConfigTA1);
  136.  
  137.     /* Remapping TA1CCR1-3 output pin to P2.0 (red green blue LED of LED2) */
  138.     MAP_PMAP_configurePorts ((const uint8_t *) port_mapping,
  139.                              PMAP_P2MAP,
  140.                              1,
  141.                              PMAP_DISABLE_RECONFIGURATION);
  142.  
  143.     /* Set pin P2.0 - P2.2 as output pins */
  144.     MAP_GPIO_setAsPeripheralModuleFunctionOutputPin (GPIO_PORT_P2,
  145.                                                      GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2,
  146.                                                      GPIO_PRIMARY_MODULE_FUNCTION);
  147.  
  148.     /* Configure the compare functionality of Timer_A0 */
  149.     MAP_Timer_A_initCompare (TIMER_A0_BASE, &compareConfigA01);
  150.     MAP_Timer_A_initCompare (TIMER_A0_BASE, &compareConfigA02);
  151.     MAP_Timer_A_initCompare (TIMER_A0_BASE, &compareConfigA03);
  152.     /* Configure Timer_A1 for Up Mode */
  153.     MAP_Timer_A_configureUpMode (TIMER_A0_BASE, &upConfigTA0);
  154.  
  155.     /* Enabling interrupts and going to sleep */
  156.     MAP_Interrupt_enableSleepOnIsrExit();
  157.     MAP_Interrupt_enableInterrupt (INT_PORT1);
  158.     MAP_Interrupt_enableInterrupt (INT_TA1_0);
  159.  
  160.     /* Enabling MASTER interrupts */
  161.     MAP_Interrupt_enableMaster();
  162.  
  163.     /* Starting the Timer_A0 and Timer_A1 in up mode */
  164.     MAP_Timer_A_startCounter (TIMER_A0_BASE, TIMER_A_UP_MODE);
  165.     MAP_Timer_A_startCounter (TIMER_A1_BASE, TIMER_A_UP_MODE);
  166.  
  167.     while (1)
  168.     {
  169.         MAP_PCM_gotoLPM3();
  170.     }
  171. }
  172.  
  173. /*
  174.  * Port 1 interrupt handler. This handler is called whenever switches attached
  175.  * to P1.1 (S1) and P1.4 (S2) are pressed.
  176.  */
  177. void PORT1_IRQHandler(void)
  178. {
  179.     uint32_t status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P1);
  180.     MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, status);
  181.  
  182.     /* Handles S1 button press turns P1.0 LED off
  183.      * (leaves timer running for P2.0 PWM display)
  184.      */
  185.     if (status & GPIO_PIN1)
  186.     {
  187.         if (toggle) {
  188.             MAP_GPIO_setOutputLowOnPin (GPIO_PORT_P1, GPIO_PIN0);
  189.         }
  190.  
  191.         toggle = !toggle;
  192.     }
  193.  
  194.     /* Handles S2 button press - cycles through PWM CCR0 (duty-cycle off) for RGB LED
  195.      * The P1.0 is toggled on/off at this rate to indicate relative PWM setting.
  196.      */
  197.     if (status & GPIO_PIN4)
  198.     {
  199.         uint_fast16_t new_ccr0 = ta1_ccr0 >> 1;             /* divide rate by 2 */
  200.         if (new_ccr0 > 1000) {                              /* if > 1000, use as is */
  201.             ta1_ccr0 = new_ccr0;
  202.         }
  203.         else if ((new_ccr0 += (new_ccr0 >> 1)) > 700) {     /* > 700, add 1/2 value */
  204.             ta1_ccr0 = new_ccr0;
  205.         }
  206.         else {                                              /* reset to 1 sec */
  207.             ta1_ccr0 = TA1_CCR0;
  208.         }
  209.  
  210.         if (toggle) {   /* if P1.0 LED visible, turn off to start new rate */
  211.             MAP_GPIO_setOutputLowOnPin (GPIO_PORT_P1, GPIO_PIN0);
  212.         }
  213.  
  214.         /* stop Timer_A1, reinitialize up mode, set new CCR0 value, start counter */
  215.         MAP_Timer_A_stopTimer (TIMER_A1_BASE);
  216.         MAP_Timer_A_configureUpMode (TIMER_A1_BASE, &upConfigTA1);
  217.         MAP_Timer_A_setCompareValue (TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0,
  218.                                      ta1_ccr0);
  219.         MAP_Timer_A_startCounter (TIMER_A1_BASE, TIMER_A_UP_MODE);
  220.     }
  221. }
  222.  
  223. /*
  224.  * Timer A1 interrupt handler. toggles the P1.0 LED
  225.  */
  226. void TA1_0_IRQHandler(void)
  227. {
  228.     MAP_Timer_A_clearCaptureCompareInterrupt (TIMER_A1_BASE,
  229.                                               TIMER_A_CAPTURECOMPARE_REGISTER_0);
  230.  
  231.     if (toggle) {   /* if P1.0 being shown, toggle output */
  232.         MAP_GPIO_toggleOutputOnPin (GPIO_PORT_P1, GPIO_PIN0);
  233.     }
  234.  
  235.     if (ta0_ccr1 <= PWM_CCR0_MIN) {         /* if PWM countdown reaches or below min, */
  236.         ta0_ccr1 = PWM_CCR0_MIN;            /* set to min. (brightest) */
  237.         dirUp = !dirUp;                     /* change count direction */
  238.     }
  239.     else if (ta0_ccr1 >= PWM_CCR0) {        /* if PWM count up reaches or above max. */
  240.         ta0_ccr1 = PWM_CCR0;                /* set to max (dimmest) */
  241.         dirUp = !dirUp;                     /* change direction */
  242.         color += 1;                         /* change RGB color */
  243.         if (color > 3) {                    /* if greater than 3 */
  244.             color = 1;                      /* reset to 1 */
  245.         }
  246.     }
  247.  
  248.     ta0_ccr1 += dirUp ? PWM_CCR0_STEP : -PWM_CCR0_STEP;     /* decrease or increases brightness */
  249.  
  250.     /* set CCR1-3 to PWM value for currently active RGB color
  251.      * set max + 1 (off) for the other 2 non-active colors
  252.      */
  253.     MAP_Timer_A_setCompareValue (TIMER_A0_BASE,
  254.                                  TIMER_A_CAPTURECOMPARE_REGISTER_1,
  255.                                  (color == 1) ? ta0_ccr1 : PWM_CCR0 + 1);
  256.     MAP_Timer_A_setCompareValue (TIMER_A0_BASE,
  257.                                  TIMER_A_CAPTURECOMPARE_REGISTER_2,
  258.                                  (color == 2) ? ta0_ccr1 : PWM_CCR0 + 1);
  259.     MAP_Timer_A_setCompareValue (TIMER_A0_BASE,
  260.                                  TIMER_A_CAPTURECOMPARE_REGISTER_3,
  261.                                  (color == 3) ? ta0_ccr1 : PWM_CCR0 + 1);
  262.  
  263. /* equivalent but long way to do it */
  264. //    switch (color) {
  265. //    case 1:
  266. //        MAP_Timer_A_setCompareValue (TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, ta0_ccr1);
  267. //        MAP_Timer_A_setCompareValue (TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2, PWM_CCR0 + 1);
  268. //        MAP_Timer_A_setCompareValue (TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_3, PWM_CCR0 + 1);
  269. //        break;
  270. //    case 2:
  271. //        MAP_Timer_A_setCompareValue (TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, PWM_CCR0 + 1);
  272. //        MAP_Timer_A_setCompareValue (TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2, ta0_ccr1);
  273. //        MAP_Timer_A_setCompareValue (TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_3, PWM_CCR0 + 1);
  274. //        break;
  275. //    case 3:
  276. //        MAP_Timer_A_setCompareValue (TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, PWM_CCR0 + 1);
  277. //        MAP_Timer_A_setCompareValue (TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2, PWM_CCR0 + 1);
  278. //        MAP_Timer_A_setCompareValue (TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_3, ta0_ccr1);
  279. //        break;
  280. //    }
  281.  
  282. }
  283.  
RAW Paste Data