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.
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)); } }
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