#include /* type definitions for the IAR MSP430 compiler */ typedef unsigned char uint8; typedef signed char int8; typedef unsigned short uint16; typedef signed short int16; typedef unsigned long uint32; typedef signed long int32; void Init_USI_I2C_SLAVE(void); void USI2_BUGFIX(void); void sirc_transmit(unsigned short data); void goertzel(); void sound_on(); void sound_off(); //define LED_ENABLE (P1DIR |= 0x01) #define GREEN_LED_ON (P1OUT |= 0x01) #define GREEN_LED_OFF (P1OUT &= ~0x01) #define GREEN_LED_TOGGLE (P1OUT ^= 0x01) #define RED_LED_ON (P1OUT |= 0x02) #define RED_LED_OFF (P1OUT &= ~0x02) #define RED_LED_TOGGLE (P1OUT ^= 0x02) volatile long dummy; volatile uint16 sample; volatile uint8 sample_ready = 0; void main(void) { WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer DCOCTL = CALDCO_16MHZ; // Set DCO for 1MHz using BCSCTL1 = CALBC1_16MHZ; // calibration registers //BCSCTL3 |= LFXT1S1; // use VLOCLK for ACLK //BCSCTL3 |= XCAP_2; // 10pf P1SEL = 0x00; // All P1.x port function P1DIR = 0x03; // All P1.x direction: output on 0,1, input on rest P1OUT = 0x00; // All P1.x reset P1REN = 0x08; // enable pull up/down on P1.3 P1OUT |= 0x08; // pull it up //P1DIR |= 0x04; //P1OUT |= 0x04; //for (dummy = 0; dummy<1000000; dummy++); //GREEN_LED_ON; //RED_LED_ON; //GREEN_LED_OFF; //RED_LED_OFF; //IE1 |= WDTIE; // Enable WDT interrupt Init_USI_I2C_SLAVE(); // Initialize I2C as Slave __enable_interrupt(); while(1) LPM0; } /***********************************************************/ /* SIRC transmission using WDT and A2 */ /* This code assumes that SMCLK runs at 16MHz */ /***********************************************************/ #if 1 unsigned short sirc_periods; unsigned short sirc_data; signed char sirc_bits_sent; signed short sirc_pulse; unsigned char sirc_wdt_counter; void sirc_transmit(unsigned short data) { sirc_data = data; //TACCR0 = 26 - 1; // 1MHz clock, PWM Period ~ 38kHz //TACCR0 = 25 - 1; // 1MHz clock, PWM Period ~ 40kHz //TACCR0 = 25 - 1; // 1MHz clock, PWM Period ~ 40kHz TACCR0 = 400 - 1; TACTL = TASSEL1+TACLR; // SMCLK, Clear TA TACCR1 = 133; // CCR1 PWM Duty Cycle TACCTL1 = OUTMOD_7; // CCR1 reset/set TACTL |= MC0; // Start TA in up mode P1SEL |= 0x04; // enable TA1 on P1.2 P1DIR |= 0x04; // output direction //TACCTL0 = CCIE; // Enable CCR0 interrupt sirc_periods = 0; sirc_pulse = 4; // start with 4 on periods sirc_wdt_counter = 0; sirc_bits_sent = 0; WDTCTL = WDTPW+WDTTMSEL+WDTCNTCL+WDTIS0+WDTIS1; // interval timer, use SMCLCK, reset, every 64 clocks IE1 |= WDTIE; // Enable WDT interrupt } #pragma vector=WDT_VECTOR __interrupt void watchdog_timer (void) { if (sirc_wdt_counter++ == 150) { sirc_periods++; sirc_wdt_counter = 0; sirc_pulse--; if (sirc_pulse > 0) return; if (sirc_pulse == 0) { P1SEL &= ~0x04; // enable P1.2 instead of TA1 P1OUT &= ~0x04; // turn it off for one period return; } if (sirc_bits_sent < 12) { P1SEL |= 0x04; // enable TA1 on P1.2 if ((sirc_data >> sirc_bits_sent) & 1) sirc_pulse = 2; else sirc_pulse = 1; sirc_bits_sent++; } if (sirc_periods == 75) { // 45ms, start another transmission sirc_periods = 0; sirc_bits_sent = 0; sirc_pulse = 4; P1SEL |= 0x04; // enable TA1 on P1.2 } } //_BIC_SR_IRQ(LPM3_bits); // Clear LPM3 bits from 0(SR) } #endif /***********************************************************/ /* i2c code */ /***********************************************************/ #if 1 static short USI_OA; // Storage for Own Address Compare Value static short USI_SA; // Storage for Slave Address Received static unsigned char USIData; // Storage for Received Data static signed char i2c_byte_count; #define I2C_OA (0x44) //#define I2C_OA (0x48) static unsigned int ProgramMode; // Current program mode enum { PM_IDLE, // Program Mode - IDLE (Slave Idle Mode) PM_SA_RECD, // Program Mode - SA_RECD (Slave Address Receive) PM_RCVR_DATA_PREP, // Program Mode - RCVR_DATA_PREP (Receiver Data Control Setup) PM_XMIT_DATA_PREP, // Program Mode - XMIT_DATA_PREP (Transmitter Data Control Setup) PM_DATA_RECD, // Program Mode - DATA_REC (Data Receive) PM_DATA_SENT // Program Mode - DATA_SEND (Data Send) }; void Init_USI_I2C_SLAVE(void) { USI_OA = I2C_OA*2; USIData = 0x00; ProgramMode = PM_IDLE; USISRL = 0xFF; USICKCTL = USICKPL; // USICLK=SCL (Inverted) USICTL1 |= USII2C+USISTTIE; // USI in I2C Mode, Enable USISTTIFG Interrupts USICTL0 = USIPE7+USIPE6+USISWRST; // USI Port Control for P1.7 and P1.6 P1REN |= 0xC0; // Enable Pull-up/down Option P1OUT |= 0xC0; // Select Pull-up for P1.7 and P1.6 //P1DIR = 0xFF; // P1.0, P1.1, and P1.4 As output //P1SEL |= 0xC0; // USICNT = 0x08; // USICNT 8-bits USICTL0 &= ~USISWRST; // Clear Reset of USI } //pragma vector=USI_VECTOR __interrupt void usi_isr (void) { if (USICTL1 & USISTTIFG) { // Was Start Condition Detected? USICTL0 &= ~USIOE; // Clear Output Enable USICNT = 0x08; // Load USICNT for 8-bits Slave Address receive USICTL1 &= ~USISTTIFG; // Clear USISTTIFG Start Interrupt Flag USICTL1 |= USIIE; // Enable USIIFG Interrupt ProgramMode = PM_SA_RECD; // Receive Slave Address } else { switch (ProgramMode) { case PM_IDLE : // Program Mode - IDLE (Slave Idle Mode) USICNT = 0x08; // Keep Loading USICNT While IDLE break; case PM_SA_RECD : // Program Mode - SA_RECD (Slave Address Received, If Match then Acknowledge, else Idle) USI_SA = USISRL; USI_SA &= 0xFE; // Remove Read/Write Bit if (USI_SA == 0x44) { // Slave Address Match --> Send Acknowledge i2c_byte_count = 0; if (USISRL & 0x01) { ProgramMode = PM_XMIT_DATA_PREP; // Generate Slave Address Ack -> Transmitter Data Control Setup } else { //USIData = 0; // clear data storage ProgramMode = PM_RCVR_DATA_PREP; // Generate Slave Address Ack -> Receiver Data Control Setup } USICTL0 |= USIOE; // Set Output Enable USISRL = 0x00; // Load USISRL for Acknowledge // USICNT = 0x01; // Load USICNT 1-bit transmit ACK (Expected Operation) USI2_BUGFIX(); // Bug Fix for Issue with USI Ack Generation break; } else { // Slave Address Not Matched --> Do not Acknowledge and return to IDLE ProgramMode = PM_IDLE; // Idle State - Wait For USISTTIFG USICTL0 &= ~USIOE; // Clear Output Enable USISRL = 0xFF; // Load USISRL for No Acknowledge // USICNT = USISCLREL+0x01; // Load USICNT 1-bit transmit NAck (Expected Operation) // // Disable SCL Holding (Start Condition Must Reset) USI2_BUGFIX(); // Bug Fix for Issue with USI NAck Generation USICNT = USISCLREL; // Disable SCL Holding (Start Condition Must Reset) USICTL1 &= ~USIIE; // Clear USIIFG Interrupt Enable break; } case PM_RCVR_DATA_PREP : // Program Mode - RCVR_DATA_PREP (Receiver Data Setup). USICTL0 &= ~USIOE; // Clear Output Enable USICNT = 0x08; // Load USICNT for 8-bits Data to Receive ProgramMode = PM_DATA_RECD; // Data Received - I2C Slave received Data from Master break; case PM_XMIT_DATA_PREP : // Program Mode - XMIT_ACK_SENT (Transmitter Acknowledge Sent) --> Transmit Data Setup. USICTL0 |= USIOE; // Set Output Enable USISRL = USIData; // Fixed Data Load USIData++; // sivan, increment USICNT = 0x08; // Load USICNT for 8-bits Data to Send ProgramMode = PM_DATA_SENT; // Data Sent - I2C Slave sent Data to Master break; case PM_DATA_RECD : // Program Mode - DATA_RECD (Data Received) --> Send Acknowledge //i2c_byte_count++; //USIData <<= 8; //shift the previous bytes to the left (low-order byte first) USIData = USISRL; // Store USISRL Data if (USIData == 1) sound_on(); if (USIData == 0) sound_off(); //if (i2c_byte_count == 2) { //P1OUT |= 0x01; // Set P1.0 LED on //sirc_transmit(USIData); //sound(); //} USICTL0 |= USIOE; // Set Output Enable USISRL = 0x00; // Load USISRL for Acknowledge //USICNT = 0x01; // Load USICNT 1-bit transmit ACK (Expected Operation) USI2_BUGFIX(); // Bug Fix for Issue with USI Ack Generation ProgramMode = PM_RCVR_DATA_PREP; // Receiver Acknowledge Sent break; case PM_DATA_SENT : // Program Mode - DATA_SENT (Data Sent) --> Check Acknowledge USICTL0 &= ~USIOE; // Clear Output Enable // USICNT = 0x01; // Load USICNT 1-bit transmit ACK (Expected Operation) USI2_BUGFIX(); // Bug Fix for Issue with USI Ack Generation if (USISRL & 0x01) { USICNT = 0x02; // Master NAck, Load USICNT 2-bit To accept Stop Condition or Handle Re-start USICTL1 &= ~USIIE; // Clear USIIFG Interrupt Enable ProgramMode = PM_IDLE; // Idle State - Wait For USISTTIFG } else ProgramMode = PM_XMIT_DATA_PREP; // Transmitter Acknowledge Sent break; } } } USI_ISR(usi_isr) //################################################################################ // USI2 Bug fix routines // //################################################################################ void USI2_BUGFIX(void) { P1OUT ^= 0x02; while (P1IN & 0x40){} // Test SCL P1(6) LOW USICNT = USISCLREL+0x01; while ((P1IN & 0x40) == 0){} // Test SCL P1(6) HIGH while (P1IN & 0x40){} // Test SCL P1(6) LOW USICNT = 0x00; // Clear USISCLREL P1OUT &= ~0x02; } #endif