clock stuff: section 8.12.3 page 21-22 Clock System (CS) and Clock Distribution: section 9.10.2 page 44 for LaunchPad, Goal: To slightly slow down the DCO frequency by 4.348% ******************************************************************** MSP430FR2xx User Guide Clock Notes page 102 showing After PUC, DCO locked by FLL operation with XT1CLK is selected by default. The FLL stabilizes MCLK and SMCLK to 1 MHz and fDCOCLKDIV = 1 MHz. {note: page 116 SELREF default 0h which is XT1CLK} [if XT1CLK selected by default, then external pins would be XT1 but also on this page showing "At power up, the default operation is I/O"] {note: page 120 Table 3-10 XT1BYPASS default internal (not pins)} [further down the page 102 showing] A default monitor is engaged with XT1 oscillation. If XT1 is used but does not work properly, fault protection logic forces REFO as the FLL reference clock. page 114 Table 3-5 CSCTL1 register (default) showing DCO range select 2 MHz but FLLD (divider) is 2 page 117 Table 3-8 MCLK & SMCLK source default is DCOCLKDIV {so according to diagram page 100, result is default both 1MHz} **************************************************************** With SMCLK = 1MHz, divide by 32 to get 31,250 Hz MSP430FR2xx User Guide UART Notes After a PUC, the UCSWRST bit is automatically set, keeping the eUSCI_A in a reset condition. When set, the UCSWRST bit sets the UCTXIFG bit and resets the UCRXIE, UCTXIE, UCRXIFG, UCRXERR, UCBRK, UCPE, UCOE, UCFE, UCSTOE, and UCBTOE bits. Clearing UCSWRST releases the eUSCI_A for operation. A transmission is initiated by writing data to UCAxTXBUF. When this occurs, the baud-rate generator is enabled, and the data in UCAxTXBUF is moved to the transmit shift register on the next BITCLK after the transmit shift register is empty. UCTXIFG is set when new data can be written into UCAxTXBUF. defaults starting page 593 Table 22-8 no parity, LSB first, 8-bit, 1 stop bit, UART mode, Async BRCLK source = UCLK(?) change to SMCLK perhaps ************************************************************************* when DCO is 16 MHz and MCLK (/64) is 250 KHz and SMCLK (/8) is 31,250 Hz then a midi bit is 32 microsec, sending 85d or 55h message 256 usec long appears as |_|~|_|~|_|~|_|~|_| = 64 + 16 + 4 + 1 180 85 stop shows: l l l h l h h l h h - l h l h l h l h l h - l l l l l l l h l h = 64 S2 shows : l l l h l h h l h h - l h l h l h l h l h - l h h h h h h l l h = 63 S1 shows : l l l h l h h l h h - l h l h l h l h l h - l h l l l l l h l h = 65 So I can program the device to send a string of messages (85d or 55h) and measure the signal to figure out how to adjust the register values. ***************************************************************** UART alt pin 12 - P1.5/UCA0RXD(uart)/UCA0SOMI(spi)/TA0.2(timer)/TMS(jtag) pin 13 - P1.4/UCA0TXD(uart)/UCA0SIMO(spi)/TA0.1(timer)/TCK(jtag) The eUSCI_A and eUSCI_B are connected either from P1 port or P2 port, it can be selected from the USCIARMP of SYSCFG3 or USCIBRMP bit of SYSCFG2 PIN (USCIARMP = 0) UART P1.4 TXD (pin 13 on target) not used (used on LaunchPad) P1.5 RXD (pin 12 on target) not used (used on LaunchPad) half moon switch J1 tip to pin 1 (P1.1) low input = slow J1 ring to pin 2 (P1.0) low input = fast J1 when both are hi then = stop for midi channel 5 For Slow we need CC#85 value 0 (to 63) = 180 85 63 for Stop we need CC#85 value 64 = 180 85 64 for Fast we need CC#85 value (65 to) 127 = 180 85 65 midi jacks - output can be type A (3.5mm) or type B (2.5mm) UCATxD P2.0 pin 8 -> buf OE pin 13 (pin 11->R4->J2 tip (A) altJ2 ring (B)) UCARxD P2.1 pin 7 <- buf out pin 8 (pin 10 -> gnd) pin 9 midi in 47K -> 5v SpyByWire pin 3 SBWtck pin 4 SBWtdio ******************************************************************* for 2422 (target): pin 14 is DO NOT CONNECT pin 3 = SBWTCK pin 4 = SPWTDIO pin 5 = Vcc pin 6 = Vss pin 7,8 P2.0 & P2.1 P2SELx = 01 is UCA0Tx - UART function (P2.0 & P2.1 P2DIR.x - n/a) pin 9 P2.2 P2SELx = 00 is I/O P2.2 P2DIR.x = 0 is input P1.0 & P1.1 (pin 1,2) P1DIR.x = 0 is input P1.0 & P1.1 P1SELx = 00 I/O P1.2,P1.3,P1.4,P1.5,P1.6,P1.7 (pin 16,15,13,12,11,10) P1DIR.x = 0 is input P1.2 & P1.3 & P1.4 P1SELx = 00 is I/O setup: clocks, UART, ports, active mode, timer, activate UART read ports 1.0 & 1.1 and store in RAM (00, 01, or 10) code loop: start snooze timer (20 ms?) check ports against stored value: if different, store and send MIDI snooze again -> back to read ports ******************************************************************** to transmit the MIDI code after UART is setup: write status byte to UCAxTXBUF and wait for UCTXIFG to be set then write first data byte, wait for UCTXIFG, write second data byte ******************************************************************** Here's the code: /* * MSP-EXP430FR2433 UART Transmitter Program (Polling Version) * * This version uses a polling loop for button state checking and implements * software debouncing using Timer A0. Interrupts are disabled. * * 1. Clock: DCO=2MHz, MCLK=1MHz, SMCLK=1MHz (Default). * 2. UART Baud Rate: 31,250 bps (using 1 MHz SMCLK, UCBRW=32). * 3. Timer A0: Implements a single 5-second wait and a 20ms debouncing wait. * 4. Button Logic (Active Low, Pull-ups): * - STOP (P2.3=Hi, P2.7=Hi): Sends [180, 85, 64] * - SLOW (P2.3=Hi, P2.7=Low): Sends [180, 85, 63] * - FAST (P2.3=Low, P2.7=Hi): Sends [180, 85, 65] * * NOTE: Timer peripherals are correctly set to Timer A0 (TA0). */ #include // Enumeration for button states typedef enum { MODE_STOP = 64, MODE_SLOW = 63, MODE_FAST = 65 } Mode; // Function prototypes void UART_send_packet(unsigned char byte3); void timer_wait_5s(void); void timer_wait_20ms(void); Mode get_current_mode(void); void main(void) { Mode previous_mode = MODE_STOP; Mode new_mode; // Stop watchdog timer WDTCTL = WDTPW | WDTHOLD; // ========================================================================= // 1. Clock System Configuration (Using System Defaults - SMCLK = 1 MHz) // ========================================================================= __bis_SR_register(SCG0); // Disable global interrupts during clock config __bic_SR_register(SCG0); // Re-enable interrupts // ========================================================================= // 2. GPIO Configuration (Buttons S1/S2 and UART) // ========================================================================= // 2a. Configure Buttons S1 (P2.3) and S2 (P2.7) P2DIR &= ~(BIT3 | BIT7); // Set P2.3 and P2.7 as inputs P2REN |= (BIT3 | BIT7); // Enable pull-up/pull-down resistors P2OUT |= (BIT3 | BIT7); // Configure as pull-up resistors (P2OUT set = pull-up) // P2IE is not set - Interrupts are disabled for polling mode P2IFG = 0; // Clear all P2 interrupt flags // 2b. Configure UART Pins (P1.4 Tx, P1.5 Rx) for eUSCI_A0 P1SEL0 |= (BIT4 | BIT5); P1SEL1 &= ~(BIT4 | BIT5); // Disable the unused pins to save power PM5CTL0 &= ~LOCKLPM5; // ========================================================================= // 3. eUSCI_A0 (UART) Configuration (Using 1 MHz SMCLK) // ========================================================================= UCA0CTLW0 |= UCSWRST; // Put eUSCI in reset for configuration UCA0CTLW0 |= UCSSEL__SMCLK; // Select SMCLK as source (1 MHz default) UCA0BRW = 32; // Integer division factor for 31,250 bps UCA0MCTLW = 0x0000; // No modulation UCA0CTLW0 &= ~UCSWRST; // Initialize eUSCI (release from reset) // ========================================================================= // 4. Initial 5-Second Wait & Main Loop // ========================================================================= timer_wait_5s(); // Start polling loop (no low power mode is used since we are actively polling) while(1) { // 1. Read the current unsettled mode (State A) new_mode = get_current_mode(); // 2. Check for a potential state change if (new_mode != previous_mode) { // 3. Wait 20ms to debounce timer_wait_20ms(); // 4. Read the state again (State B) Mode settled_mode = get_current_mode(); // 5. If the state is still different (change settled) if (settled_mode != previous_mode) { // Send the UART message corresponding to the new mode UART_send_packet((unsigned char)settled_mode); // Update the stored mode previous_mode = settled_mode; } } // Small delay to prevent constantly hammering the CPU/Timer timer_wait_20ms(); } } /** * @brief Reads the state of P2.3 (S1) and P2.7 (S2) and returns the defined Mode. */ Mode get_current_mode(void) { unsigned int p2_state = P2IN; unsigned int s1_state = p2_state & BIT3; // 0 if pressed, BIT3 if released unsigned int s2_state = p2_state & BIT7; // 0 if pressed, BIT7 if released // STOP: P2.3 High (Released) AND P2.7 High (Released) if (s1_state && s2_state) { return MODE_STOP; // 64 } // SLOW: P2.3 High (Released) AND P2.7 Low (Pressed) else if (s1_state && !s2_state) { return MODE_SLOW; // 63 } // FAST: P2.3 Low (Pressed) AND P2.7 High (Released) else if (!s1_state && s2_state) { return MODE_FAST; // 65 } // Default to STOP if an ambiguous state (both pressed) occurs, though // this shouldn't happen with the current logic. return MODE_STOP; } /** * @brief Sends a 3-byte packet over the UART (eUSCI_A0). */ void UART_send_packet(unsigned char byte3) { unsigned char packet[] = {180, 85, byte3}; while (!(UCA0IFG & UCTXIFG)); UCA0TXBUF = packet[0]; while (!(UCA0IFG & UCTXIFG)); UCA0TXBUF = packet[1]; while (!(UCA0IFG & UCTXIFG)); UCA0TXBUF = packet[2]; } /** * @brief Blocks execution for exactly 5.0 seconds using Timer A0. * * Uses SMCLK (1 MHz) divided by 64 (15,625 Hz). Ticks needed: 78,125. */ void timer_wait_5s(void) { // Configure TA0: SMCLK / 64 (ID=3, IDEX=7) -> 15625 Hz TA0CTL = TASSEL_2 | MC__STOP | TACLR | ID_3; TA0EX0 = TAIDEX_7; // First count: 65536 ticks TA0CCR0 = 65536 - 1; TA0CTL |= MC__UP; while (!(TA0CCTL0 & CCIFG)); // Check CCIFG in TA0CCTL0 TA0CCTL0 &= ~CCIFG; // Clear CCIFG // Second count: remaining 12589 ticks TA0CCR0 = 12589 - 1; TA0CTL |= MC__UP; while (!(TA0CCTL0 & CCIFG)); // Check CCIFG in TA0CCTL0 // Ensure timer is completely stopped and reset TA0CTL = MC__STOP | TACLR; } /** * @brief Blocks execution for exactly 20 milliseconds using Timer A0. * * Uses SMCLK (1 MHz) divided by 1 (1,000,000 Hz). Ticks needed: 20,000. */ void timer_wait_20ms(void) { // Configure TA0 to use SMCLK / 1 -> 1 MHz TA0CTL = TASSEL_2 | MC__STOP | TACLR; TA0CCR0 = 20000 - 1; TA0CTL |= MC__UP; while (!(TA0CCTL0 & CCIFG)); // Check CCIFG in TA0CCTL0 // Ensure timer is completely stopped and reset TA0CTL = MC__STOP | TACLR; } ******************************************************************* 2. Load Program Only If you only want to flash the code without starting the interactive debugger (e.g., for a final release version), you can use the Load option. Connect the Hardware: Plug in your LaunchPad. Load Program: Go to Run -> Load -> Load Program... Browse: A dialog will open, and you'll typically select the .out file located in your project's Debug folder (e.g., LaunchPad midiator 1.out). Load: Click OK.