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.

CCS/MSP432P401R: EXP432P401R-MSP TI

Part Number: MSP432P401R

Tool/software: Code Composer Studio

I am trying to communicate with a Gamecube controller using the MSP432. I got the controller to send the data to me but I am having difficulties receiving the data.

The controller works by first sending a string of 24bits to the controller and then it responds with 64bits of data. A one is represented by a 1us low and 3us high and a zero is 3us low followed by 1us high.  If you need more information here is a good form on how the controller works: https://os.mbed.com/users/christopherjwang/code/gamecube_controller/wiki/Homepage

Currently, I am using TimerA to generate and receive the signals to and from the controller. I was successful in getting the controller to respond with the full 64bits of data but I am having troubles with capturing the data coming from the GameCube controller. I use TimerA in capture mode and I have interrupts setup to capture on both rising and falling edges. Now, I have my MCLK running at 48Mhz and my SMCLK at 12Mhz so I should have roughly 12 clock cycles per microsecond. I'm trying to read the time that the GameCube controller pulls the resistor low. If the GameCube controller sends a zero there should be about 36 clock cycles (3us) low and 12 clock cycles (1us) low for a one. The MSP432 is running at 48Mhz so I don't think computation time is the issue but I could be wrong.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#include "msp432.h"
#include "stdio.h"
#include "stdint.h"
#include "msoe_lib_lcd.h"
#include "msoe_lib_clk.h"
#include "msoe_lib_delay.h"
#include "float.h"

#define one_count 12    // # of clocks low for a 1
#define zero_count 36   // # of clocks low for a 0

void Pin_Setup(void);
void TIMERA_setup(void);
void Transmit(void);
void Receive(void);
void Bit_To_Count(int datain);
void Controller_Inputs(void);
void Byte_Extractor(int startbit,int* result);

uint8_t bitcountvalues[25];
int bit_tracker = 24;
uint64_t ControllerStatus = 0;
int count;

void main(void){

    Clock_Init_48MHz();
    Delay_48MHz_sec(1);
    Bit_To_Count(0x400300); // Converts binary to times for data transmission
    Pin_Setup();    // Setup pins for data transmission
    TIMERA_setup(); // Setup timerA for data transmission
    _enable_interrupts();
    _delay_cycles(1000);

    while(1){

        Transmit(); // Polls for data from controller
        Receive(); // Captures data from controller
        Controller_Inputs(); // Prints controller inputs
        Delay_48MHz_sec(1); // 1 second delay

    }
}

void Transmit(void){

    TIMER_A1->CTL |= 0x0010; // Start data transmission
    TIMER_A1->CCR[1] = bitcountvalues[24];  // Load counts for first bit
    bit_tracker = 24;   //Reset bit tracker
    while(bit_tracker>=0){} // waits for transmission to complete
    TIMER_A1->CTL &= ~0x0010; // Stop data transmission
    TIMER_A1->R = 0; // Clear count

}

void Receive(void){

    TIMER_A3->CTL |= 0x0010; // Start data retrieval
    bit_tracker=64;
    while(bit_tracker>=0){} // Wait for data retrieval to complete
    TIMER_A3->CTL &= ~0x0010; // Stop data transmission

}

void TA1_N_IRQHandler(void){

    TIMER_A1->CCTL[1] &=~0x0001; // Clear flag
    TIMER_A1->CCTL[1] |= 0x0004; // Set output low

}

void TA1_0_IRQHandler(void){

    TIMER_A1->CCTL[1] &= ~0x0004; // Set output high
    TIMER_A1->CCR[1] = bitcountvalues[bit_tracker]; // Load next bit count into timer
    TIMER_A1->CCTL[0] &=~0x0001; // Clear flag
    bit_tracker--; // Move to next bit in sequence

}

void TA3_N_IRQHandler(void){


    if(TIMER_A3->IV == 0x02){
        int capture = TIMER_A3->CCR[1];
        if((TIMER_A3->CCTL[1] & 0x08)){ // Rising edge only
            if(capture<=15) // Is it a one?
                ControllerStatus |= (1<<(bit_tracker-1)); // Sets 1 in location of current data transfer
            else
                ControllerStatus &= ~(1<<(bit_tracker-1)); // Sets 0 in location of current data transfer

            bit_tracker--; // Move to next bit
        }
    }

}

void Bit_To_Count(int datain){

    int i;
    for(i=24;i>0;i--){
        if(datain & (1<<(i-1)))
            bitcountvalues[i] = one_count;
        else
            bitcountvalues[i] = zero_count;

        bitcountvalues[0] = one_count; // Set end bit
    }

}

void TIMERA_setup(void){

    NVIC->IP[10] = 0x20;
    NVIC->IP[11] = 0x20;
    NVIC->ISER[0] |= 0x0C00; //Interrupts for TA1 for TX
    TIMER_A1->CTL = 0x0200; //Timer is initially stopped, set 2nd nibble to 1 to start
    TIMER_A1->CCR[1] = 0;
    TIMER_A1->CCR[0] = 48; //Total of 4us for 1 bit
    TIMER_A1->CCTL[0] = 0x0010;
    TIMER_A1->CCTL[1] = 0x0014;

    TIMER_A3->CTL = 0x0200;
    TIMER_A3->CCTL[1] = 0xC110;
    NVIC->IP[15] = 0x10;
    NVIC->IP[14] = 0x10;
    NVIC->ISER[0] |= 0xC000; //Interrupts for TA3 for TX

//    TIMER_A0->CTL = 0x0204;
//    TIMER_A0->CCTL[0]= 0x0900;

}

void Pin_Setup(void){

    P7->SEL0 |= 0x80;   //Set P7.7 in PWM mode
    P7->SEL1 &= ~0x80;
    P7->DIR |= 0x80;    //Set P7.7 as an output

    P10->SEL0 |= 0x20;
    P10->SEL1 &= ~0x20;
    P10->DIR &= ~0x20;    //Set P10.5 as an input
    P8->REN |= 0x01;

    P8->DIR &= ~0x01;   //Set as input
    P8->OUT &= ~0x01;   //enable put down resistor
    P8->REN |= 0x01;

}

void Controller_Inputs(void){

    printf("Start is: %d\n",(((ControllerStatus & 1)<<60)&&1));
    printf("Y is: %d\n",(((ControllerStatus & 1)<<59)&&1));
    printf("X is: %d\n",(((ControllerStatus & 1)<<58)&&1));
    printf("B is: %d\n",(((ControllerStatus & 1)<<57)&&1));
    printf("A is: %d\n",(((ControllerStatus & 1)<<56)&&1));
    printf("1 is: %d\n",(((ControllerStatus & 1)<<55)&&1));
    printf("L is: %d\n",(((ControllerStatus & 1)<<54)&&1));
    printf("R is: %d\n",(((ControllerStatus & 1)<<53)&&1));
    printf("Z is: %d\n",(((ControllerStatus & 1)<<52)&&1));
    printf("D-Up is: %d\n",(((ControllerStatus & 1)<<51)&&1));
    printf("D-Down is: %d\n",(((ControllerStatus & 1)<<50)&&1));
    printf("D-Right is: %d\n",(((ControllerStatus & 1)<<49)&&1));
    printf("D-Left is: %d\n",(((ControllerStatus & 1)<<48)&&1));

    int value;
    Byte_Extractor(47,&value);
    printf("Joystick X Value is: %d\n",value);
    Byte_Extractor(39,&value);
    printf("Joystick X Value is: %d\n",value);
    Byte_Extractor(31,&value);
    printf("Joystick X Value is: %d\n",value);
    Byte_Extractor(23,&value);
    printf("Joystick X Value is: %d\n",value);
    Byte_Extractor(15,&value);
    printf("Joystick X Value is: %d\n",value);
    Byte_Extractor(7,&value);
    printf("Joystick X Value is: %d\n",value);

}



void Byte_Extractor(int startbit,int* result){

    int i;
    for(i=0;i<8;i++){
        *result |= (((ControllerStatus & (1<<startbit-i)) && 1)<<(7-i));
    }

}

  • 1) You won't know until you time it. If you have a scope, wiggle a GPIO on entry/exit. If you don't, store TIMER_A1->R on entry/exit.

    2) You have a 2us deadline (2 edges in 4us). This is rather tight. Even at 48MHz, you shouldn't count on getting 48 CPU clocks every microsecond -- there's no I-cache, only a single (4-word) flash buffer, and 1 flash wait state. So your ISR shouldn't be thinking much -- I suggest you just store CCR1 and CCTL1 and unwind it all afterward.

    This bitstream is fast enough that you probably aren't getting any benefit from the ISR. Consider just polling CCIFG instead.
  • Currently, I do not have access to an oscilloscope with two channels so I was unable to test when it is entering the interrupt. I will try this later and update you when I get the chance. 

    As for capturing the data from the GameCube controller, I tried what you suggested. I disabled interrupts and waited for the CCIFG flag to be raised and the input to be high. I am only getting counts of zero in my CCR register. I also tried a second method which I only watched the input pin and when there was a rising edge on the pin I stored the value of the CCR register. This also gave me only zeros. 

    This is what I have my timer set to:

    TIMER_A3->CTL = 0x0210; //SMCLK, UP mode
    TIMER_A3->CCTL[1] = 0xC900; //Capture on rise/fall, no interrupt

    Here is what you suggested to do:

    void Receive(void){
    
        for(bit_tracker=63;bit_tracker>=0;bit_tracker--){ //Data collection
            TIMER_A3->CCTL[1] &= ~0x01; //Clear CCIFG flag
            while((TIMER_A3->CCTL[1] & 0x09) != 0x09){} //Wait for CCIFG flag and rising edge
            inputdata[bit_tracker] = TIMER_A3->CCR[1]; //Store count for low time
        }
    
        for(bit_tracker=63;bit_tracker>=0;bit_tracker--){ //Data interpretation 
            if(inputdata[bit_tracker]<=15) // Is it a one?
                ControllerStatus |= (1<<(bit_tracker)); // Sets 1 in location of current data transfer
            else
                ControllerStatus &= ~(1<<(bit_tracker)); // Sets 0 in location of current data transfer
        }
    
    }

    Here is the other method I tried:

    void Receive(void){
    
        for(bit_tracker=63;bit_tracker>=0;bit_tracker--){ //Data collection
            while(TIMER_A3->CCTL[1] & 0x08){} //Wait for signal to pull low
            while(!(TIMER_A3->CCTL[1] & 0x08)){} //Wait for signal to go high
            inputdata[bit_tracker] = TIMER_A3->CCR[1]; //Store count for time low
        }
    
        for(bit_tracker=63;bit_tracker>=0;bit_tracker--){ //Data interpretation
            if(inputdata[bit_tracker]<=15) // Is it a one?
                ControllerStatus |= (1<<(bit_tracker)); // Sets 1 in location of current data transfer
            else
                ControllerStatus &= ~(1<<(bit_tracker)); // Sets 0 in location of current data transfer
        }
    
    }

  • You're running in Up (MC=1) mode, but I don't see where you set CCR[0], so it's never counting past 0.

    When I do this kind of thing, I prefer Continuous (MC=2) mode, which allows me to subtract successive captures without any pesky modulo operations.

    [Edit: Fixed wording.]

  • It works! I completely overlooked the CCR[0] register. Once I set it I started to get nonzero counts from the GameCube controller. I had to make some other adjustments but everything seems to be working nicely now. Thank you!

    Also, here is the working code for anyone interested:

    #include "msp432.h"
    #include "stdio.h"
    #include "stdint.h"
    #include "msoe_lib_lcd.h"
    #include "msoe_lib_clk.h"
    #include "msoe_lib_delay.h"
    #include "float.h"
    
    #define one_count 12    // # of clocks low for a 1
    #define zero_count 36   // # of clocks low for a 0
    
    void Pin_Setup(void);
    void TIMERA_setup(void);
    void Transmit(void);
    void Receive(void);
    void Bit_To_Count(int datain);
    void Controller_Inputs(void);
    void Analog_Button_Inputs(int* Button,int bit);
    
    int bitcountvalues[25];
    int inputdata[64];
    int bit_tracker = 24;
    uint32_t ButtonInputs = 0;
    int Joystick_X = 0;
    int Joystick_Y = 0;
    int Cstick_X = 0;
    int Cstick_Y = 0;
    int Left_Button = 0;
    int Right_Button = 0;
    
    void main(void){
    
        Clock_Init_48MHz();
        Delay_48MHz_sec(1);
        Bit_To_Count(0x400300); // Converts binary to times for data transmission
        Pin_Setup();    // Setup pins for data transmission
        TIMERA_setup(); // Setup timerA for data transmission
        _enable_interrupts();
        _delay_cycles(1000);
    
        while(1){
    
    //        printf("Press Any Key to Continue\n");
    //        getchar();
            Transmit(); // Polls for data from controller
            Receive(); // Captures data from controller
          //  Controller_Inputs(); // Prints controller inputs
            if(ButtonInputs & (1<<12))  //Toggles onboard LED if start is pressed
                P2->OUT |= 0x01; //Turn on LED
            else
                P2->OUT &= ~0x01; //Turn off LED
    
            if(ButtonInputs & (1<<8)) //Turns on controller rubble
                Bit_To_Count(0x400301);
            if(ButtonInputs & (1<<9)) //Turns off controller rubble
                Bit_To_Count(0x400300);
    
        }
    }
    
    void Transmit(void){
    
        TIMER_A1->CTL |= 0x0010; // Start data transmission
        TIMER_A1->CCR[1] = bitcountvalues[24];  // Load counts for first bit
        bit_tracker = 24;   //Reset bit tracker
        while(bit_tracker>=0){} // waits for transmission to complete
        TIMER_A1->CTL &= ~0x0010; // Stop data transmission
        TIMER_A1->R = 0; // Clear count
    
    }
    
    void Receive(void){
    
        for(bit_tracker=63;bit_tracker>=0;bit_tracker--){ //Data collection
            while(TIMER_A3->CCTL[1] & 0x08){} //Wait for signal to pull low
            TIMER_A3->R = 0;
            while(!(TIMER_A3->CCTL[1] & 0x08)){} //Wait for signal to go high
            inputdata[bit_tracker] = (uint8_t)(TIMER_A3->CCR[1]); //Store count for low time
        }
    
        for(bit_tracker=63;bit_tracker>=48;bit_tracker--){ //Data interpretation: Buttons
            if(inputdata[bit_tracker]<=15) // Is it a one?
                ButtonInputs |= (1<<(bit_tracker-48)); // Sets 1 in location of current data transfer
            else
                ButtonInputs &= ~(1<<(bit_tracker-48)); // Sets 0 in location of current data transfer
        }
        // The following captures the analog outputs of the GameCube controller
        Analog_Button_Inputs(&Joystick_X,47);
        Analog_Button_Inputs(&Joystick_Y,39);
        Analog_Button_Inputs(&Cstick_X,31);
        Analog_Button_Inputs(&Cstick_Y,23);
        Analog_Button_Inputs(&Left_Button,15);
        Analog_Button_Inputs(&Right_Button,7);
    
    }
    
    void Analog_Button_Inputs(int* Button,int bit){
        int i;
        for(i=bit;i>=(bit-7);i--){ //Data interpretation: Buttons
            if(inputdata[i]<=15) // Is it a one?
                *Button |= (1<<(i-(bit-7))); // Sets 1 in location of current data transfer
            else
                *Button &= ~(1<<(i-(bit-7))); // Sets 0 in location of current data transfer
        }
    
    }
    
    void TA1_N_IRQHandler(void){
    
        TIMER_A1->CCTL[1] &=~0x0001; // Clear flag
        TIMER_A1->CCTL[1] |= 0x0004; // Set output low
    
    }
    
    void TA1_0_IRQHandler(void){
    
        TIMER_A1->CCTL[1] &= ~0x0004; // Set output high
        TIMER_A1->CCR[1] = bitcountvalues[bit_tracker]; // Load next bit count into timer
        TIMER_A1->CCTL[0] &=~0x0001; // Clear flag
        bit_tracker--; // Move to next bit in sequence
    
    }
    
    void Bit_To_Count(int datain){
    
        int i;
        for(i=24;i>0;i--){
            if(datain & (1<<(i-1)))
                bitcountvalues[i] = one_count;
            else
                bitcountvalues[i] = zero_count;
    
            bitcountvalues[0] = one_count; // Set end bit
        }
    
    }
    
    void TIMERA_setup(void){
    
        NVIC->IP[10] = 0x20;
        NVIC->IP[11] = 0x20;
        NVIC->ISER[0] |= 0x0C00; //Interrupts for TA1 for TX
        TIMER_A1->CTL = 0x0200; //Timer is initially stopped, set 2nd nibble to 1 to start
        TIMER_A1->CCR[1] = 0;
        TIMER_A1->CCR[0] = 48; //Total of 4us for 1 bit
        TIMER_A1->CCTL[0] = 0x0010;
        TIMER_A1->CCTL[1] = 0x0014;
    
        TIMER_A3->CTL = 0x0210; //SMCLK, UP mode
        TIMER_A3->CCTL[1] = 0xC900; //Capture on rise/fall, no interrupt
        TIMER_A3->CCR[0] = 0xFFFF;
    
    }
    
    void Pin_Setup(void){
    
        P7->SEL0 |= 0x80;   //Set P7.7 in PWM mode
        P7->SEL1 &= ~0x80;
        P7->DIR |= 0x80;    //Set P7.7 as an output
    
        P10->SEL0 |= 0x20;
        P10->SEL1 &= ~0x20;
        P10->DIR &= ~0x20;    //Set P10.5 as an input
    
        P2->DIR |= 0x01; //Set P2.0 as an output
        P2->OUT &= ~0x01; //Set P2.0 output low
    }
    
    void Controller_Inputs(void){
    
        printf("Start is: %d\n",((ButtonInputs & (1<<12))&&1));
        printf("Y is: %d\n",((ButtonInputs & (1<<11))&&1));
        printf("X is: %d\n",((ButtonInputs & (1<<10))&&1));
        printf("B is: %d\n",((ButtonInputs & (1<<9))&&1));
        printf("A is: %d\n",((ButtonInputs & (1<<8))&&1));
        printf("1 is: %d\n",((ButtonInputs & (1<<7))&&1));
        printf("L is: %d\n",((ButtonInputs & (1<<6))&&1));
        printf("R is: %d\n",((ButtonInputs & (1<<5))&&1));
        printf("Z is: %d\n",((ButtonInputs & (1<<4))&&1));
        printf("D-Up is: %d\n",((ButtonInputs & (1<<3))&&1));
        printf("D-Down is: %d\n",((ButtonInputs & (1<<2))&&1));
        printf("D-Right is: %d\n",((ButtonInputs & (1<<1))&&1));
        printf("D-Left is: %d\n",((ButtonInputs & (1<<0))&&1));
    
        printf("Joystick X Value is: %d\n",Joystick_X);
        printf("Joystick Y Value is: %d\n",Joystick_Y);
        printf("C-Stick X Value is: %d\n",Cstick_X);
        printf("C-Stick Y Value is: %d\n",Cstick_Y);
        printf("Left Button Value is: %d\n",Left_Button);
        printf("Right Button Value is: %d\n",Right_Button);
    
    }

**Attention** This is a public forum