Yuri 0 Posted May 29, 2013 Share Posted May 29, 2013 EDIT I have a new issue regarding USCI UART if ANYONE can assist! This is my only remaining major problem it seems like! Hello, I am really new to embedded systems and such, but for work I have been thrown in a bit. I have been given an MSP430 Launchpad and a DRV2603EVM-CT CapTouch board, and I have learned how to modify the firmware. But my boss is looking for software interaction. He wants the ability to plug in the boards, and load a program on his desktop, and mess with the various vibration profiles and such for his board live. Like, command prompt opens, he can scroll through a menu, pick an option, like blink an LED 4 times, that option occurs live. No debugging, ejecting, testing, etc. I feel like this should be fairly simple. I'm a mathematician with a large bit of experience using C++ only though. I am wondering if I could get any sort of guidance. Just the ability to get an LED to blink using the space bar, or a single vibration from the captouch board using the keyboard on my computer would make a world of difference. I have been scanning the internet, but it seems like all of these tutorials are for direct hardware interaction, and while they're all informative, I'm having a difficult time finding something that caters to my needs specifically. Any advice at all would be greatly appreciated. I hope I had worded this properly. If not, I can try again ~Yuri Quote Link to post Share on other sites
spirilis 1,265 Posted May 29, 2013 Share Posted May 29, 2013 Sounds straightforward enough, your firmware will have the very basics of an RTOS with a timer tick and scheduler (an overgrown while (1) loop with lots of if () statements checking flags to determine what work needs to be done) but with some kind of command interpreter and the serial port ISRs set up to cooperate (stuffing a buffer with incoming bytes and setting a flag indicating a command is ready for the main loop to act upon).Fwiw, if you look for my Charcoal grill monitor project on this forum, in the basestation subdirectory in my code (I attached it to one of the posts--I'd provide a link but I'm typing from my phone atm) you'll see an example implementation of a Command Line Interface. I still use it to this day and I've extended its featureset to support new radio-based gadgets I've designed. It connects to my Linux server so I can SSH in from anywhere and play with it.I recommend a similar app architecture, the husk of an RTOS with some type of serial command interpreter (menu is doable too).Your biggest limitation will be the available flash memory for the code. As you add more and more features the code bloat will bump you up against the limits of the chip. Keep it simple.Sent from my Galaxy Note II with Tapatalk edit: Here's my last post in that thread, with the current code posted- http://forum.43oh.com/topic/2857-charcoal-grill-smoker-monitor/?p=35535 JWoodrell 1 Quote Link to post Share on other sites
simpleavr 399 Posted May 30, 2013 Share Posted May 30, 2013 if u prefer to start w/ something simpler, try NJC's uart code as the foundation (as long as i remember, this was among the very 1st s/w uart code shared here) http://www.msp430launchpad.com/2010/08/half-duplex-software-uart-on-launchpad.html it allows u to type characters from your PC via a terminal program such as putty. it is very easy to try out and the web page has very good explanation on what's happening. once u got it working u can implement your mini command interpreter to drive leds by comparing characters received from the pc side. ex. while(1) { if (hasReceived) // If the device has recieved a value { hasReceived = false; // Clear the flag // do your stuff here based on incoming character switch (RXByte) { case 'x': P1OUT ^= BIT0; // toggle led at P1.0 break; case 'y': // whatever need to drive vibrating motor, etc break; } // end fix TXByte = RXByte; // Load the recieved byte into the byte to be transmitted Transmit(); } if (~hasReceived) // Loop again if another value has been received __bis_SR_register(CPUOFF + GIE); // LPM0, the ADC interrupt will wake the processor up. This is so that it does not // endlessly loop when no value has been Received. } Quote Link to post Share on other sites
JWoodrell 285 Posted May 30, 2013 Share Posted May 30, 2013 another alternative if you have the spare processor time to run it is you can run the mecrimus USB code, and have it enumerate as a HID keyboard. (atleast with windows) by default any "keyboard" device is sent the information when a key is pressed, so you have it tell the OS that is is a "keyboard" and the OS will feed all key presses to that USB port, you then just filter those incoming reports and when you see the key you want to act on you trigger it to act. I will fiddle with the USB code and get it to enumerate as a keyboard and confirm this works. Quote Link to post Share on other sites
Yuri 0 Posted June 3, 2013 Author Share Posted June 3, 2013 Thank you for your assistance! I feel bad that I'm still a bit lost. I had taken TI's example code for UART but noticed that the blog you linked me to had a code explanation of that. Reading that over has helped! But I still don't completely understand what I am doing. I need to meld this with a DRV2603, but the numbers seem off, so the board bricks and crashes the moment I try to boot with any sort of vibration profile in the code. I am wondering if anyone can help with that. I know it has to do with the pins, clocks, etc. But I understand none of that, really. I posted all of the code on github if that helps, but I'll copy and paste the main here, since that may be sufficient. #include "msp430g2553.h" #include "CapTouchBoard.h" #include "Actuator_Waveforms.h" #include "SimonGame.h" #include "BinaryModes.h" #include "stdbool.h" //------------------------------------------------------------------------------ // Hardware-related definitions //------------------------------------------------------------------------------ #define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0) #define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A) //------------------------------------------------------------------------------ // Conditions for 9600 Baud SW UART, SMCLK = 1MHz //------------------------------------------------------------------------------ #define UART_TBIT_DIV_2 (8000000 / (9600 * 2)) #define UART_TBIT (8000000 / 9600) //------------------------------------------------------------------------------ // Global variables //------------------------------------------------------------------------------ unsigned int txData; // UART internal variable for TX unsigned char rxBuffer; // Received UART character bool hasReceived; // No bool? #define SCROLL 250 unsigned int i; //------------------------------------------------------------------------------ // Function prototypes //------------------------------------------------------------------------------ void TimerA_UART_init(void); void TimerA_UART_tx(unsigned char byte); void TimerA_UART_print(char *string); //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer DCOCTL = 0; // Select lowest DCOx and MODx settings BCSCTL1 = CALBC1_8MHZ; // Set DCOCLK to 8MHz DCOCTL = CALDCO_8MHZ; BCSCTL1 |= DIVA_0; // ACLK/(0:1,1:2,2:4,3:8) //UNCOMMENTING BCSCTL2 MAKES MANY ERRORS // BCSCTL2 |= DIVS_3; // SMCLK/(0:1,1:2,2:4,3:8) BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO (select SMCLK source) // 8000000 Hz 9600 bps UCA0BR0 = 0x41; UCA0BR1 = 0x03; UCA0MCTL = UCBRS_3 + UCBRF_0; P1OUT = 0x00; // Initialize all GPIO P1SEL = UART_TXD + UART_RXD; // Timer function for TXD/RXD pins P1DIR = (0xFF & ~UART_RXD) ; // Set all pins but RXD to output /*****I Assumed that I would not use the buttons on the CapTouch board, so I commented them out*****/ //P1DIR |= (BUTTON1+BUTTON2+BUTTON3+BUTTON4); P2OUT = 0x40; P2SEL &= 0xBF; P2SEL2 &= 0xBF; // P2.0-P2.5 = cap sense, P2.6 = I/O P2DIR = 0x40; P3OUT = 0x00; P3SEL |= 0x04; P3DIR |= (MODE0+MODE1+MODE2+MODE3+MODE4+BIT2+BIT1+BIT0); // Set P3.0-P3.1, P3.3-P3.7 as outputs = LRA/^ERM, EN, M0-M4 // TimerA Setup // Set PWM Frequency, TimerA gives 255 counts at SMCLK frequency TA1CCR0 = 0x00FF; __enable_interrupt(); CapTouch_Init(); // Initialize the cap touch board setting and statuses Haptics_Init(); // Initialize Haptics settings //CapTouch_PowerUpSequence(); //Haptics_SendWaveform(lra_click); TimerA_UART_init(); // Start Timer_A UART TimerA_UART_print("G2xx2 TimerA UART\r\n"); TimerA_UART_print("READY.\r\n"); // for (; // { // Wait for incoming character // __bis_SR_register(LPM0_bits); // Echo received character // TimerA_UART_tx(rxBuffer); // hasReceived = true; // } while(1) { // Wait for incoming character __bis_SR_register(LPM0_bits); // Echo received character TimerA_UART_tx(rxBuffer); hasReceived = true; if(rxBuffer == '1') { TimerA_UART_print(" YOU PRESSED 1! \r\n"); __bis_SR_register(LPM0_bits); switch(rxBuffer) { case 'x' : { TimerA_UART_print(" YOU PRESSED x!\r\n"); break; } case 'y' : { TimerA_UART_print("YOU PRESSED y!\r\n"); break; } } } } } //------------------------------------------------------------------------------ // Function configures Timer_A for full-duplex UART operation //------------------------------------------------------------------------------ void TimerA_UART_init(void) { TACCTL0 = OUT; // Set TXD Idle as Mark = '1' TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int TACTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode } //------------------------------------------------------------------------------ // Outputs one byte using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_tx(unsigned char byte) { while (TACCTL0 & CCIE); // Ensure last char got TX'd TACCR0 = TAR; // Current state of TA counter TACCR0 += UART_TBIT; // One bit time till first bit TACCTL0 = OUTMOD0 + CCIE; // Set TXD on EQU0, Int txData = byte; // Load global variable txData |= 0x100; // Add mark stop bit to TXData txData <<= 1; // Add space start bit } //------------------------------------------------------------------------------ // Prints a string over using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_print(char *string) { while (*string) { TimerA_UART_tx(*string++); } } //------------------------------------------------------------------------------ // Timer_A UART - Transmit Interrupt Handler //------------------------------------------------------------------------------ #pragma vector = TIMER0_A0_VECTOR __interrupt void Timer_A0_ISR(void) { static unsigned char txBitCnt = 10; TACCR0 += UART_TBIT; // Add Offset to CCRx if (txBitCnt == 0) { // All bits TXed? TACCTL0 &= ~CCIE; // All bits TXed, disable interrupt txBitCnt = 10; // Re-load bit counter } else { if (txData & 0x01) { TACCTL0 &= ~OUTMOD2; // TX Mark '1' } else { TACCTL0 |= OUTMOD2; // TX Space '0' } txData >>= 1; txBitCnt--; } } //------------------------------------------------------------------------------ // Timer_A UART - Receive Interrupt Handler //------------------------------------------------------------------------------ #pragma vector = TIMER0_A1_VECTOR __interrupt void Timer_A1_ISR(void) { static unsigned char rxBitCnt = 8; static unsigned char rxData = 0; switch (__even_in_range(TA0IV, TA0IV_TAIFG)) { // Use calculated branching case TA0IV_TACCR1: // TACCR1 CCIFG - UART RX TACCR1 += UART_TBIT; // Add Offset to CCRx if (TACCTL1 & CAP) { // Capture mode = start bit edge TACCTL1 &= ~CAP; // Switch capture to compare mode TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0 } else { rxData >>= 1; if (TACCTL1 & SCCI) { // Get bit waiting in receive latch rxData |= 0x80; } rxBitCnt--; if (rxBitCnt == 0) { // All bits RXed? rxBuffer = rxData; // Store in global variable rxBitCnt = 8; // Re-load bit counter TACCTL1 |= CAP; // Switch compare to capture mode __bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR) } } break; } } //------------------------------------------------------------------------------ Anyways github for everything: https://github.com/CaptainSay/CapTouchTest.git Quote Link to post Share on other sites
simpleavr 399 Posted June 3, 2013 Share Posted June 3, 2013 I need to meld this with a DRV2603, but the numbers seem off, so the board bricks and crashes the moment I try to boot with any sort of vibration profile in the code. your description of your problem is vague. have u try just uart? (i.e. w/o any access to DRV2603) does it work? i can see your main loop will reply strings upon reception of command characters. does it work well before adding DRV2603 fragments? when u say the numbers are off? how do u get the numbers as u also mentioned that it crashes when boot? are u doing unit testing and if so how do u do that? many times when u put together code fragments / examples for different systems (uart, cap sense, adc, etc) the conflict will surface because of timer and port io contentions. it is alway wise "stack" code modules one by one when integrating. u should try to comment out "captouch_init(); haptic_init()" and other port initialization to make sure uart work 1st. and then add them back one by one to identify the problem maker. if u can do that, we could look inside the offending part w/ greater concentration. Quote Link to post Share on other sites
pabigot 355 Posted June 3, 2013 Share Posted June 3, 2013 Off topic, but: I may just be an old grumpy-pants, but posts that use "u" where "you" is intended really bug the living peanut butter out of me. Enough so that I don't even read them through, so won't contribute to discussions where comprehending them is important. (Absence of upper case where the language standards expect it is slightly less irritating but still disruptive. I notice that the two styles tend to appear together.) I mention this because I'm almost certainly not the only one who reacts this way. simpleavr 1 Quote Link to post Share on other sites
simpleavr 399 Posted June 3, 2013 Share Posted June 3, 2013 Thanks for advice. I shall correct my laziness. pabigot 1 Quote Link to post Share on other sites
Yuri 0 Posted June 3, 2013 Author Share Posted June 3, 2013 your description of your problem is vague. have u try just uart? (i.e. w/o any access to DRV2603) does it work? i can see your main loop will reply strings upon reception of command characters. does it work well before adding DRV2603 fragments? when u say the numbers are off? how do u get the numbers as u also mentioned that it crashes when boot? are u doing unit testing and if so how do u do that? many times when u put together code fragments / examples for different systems (uart, cap sense, adc, etc) the conflict will surface because of timer and port io contentions. it is alway wise "stack" code modules one by one when integrating. u should try to comment out "captouch_init(); haptic_init()" and other port initialization to make sure uart work 1st. and then add them back one by one to identify the problem maker. if u can do that, we could look inside the offending part w/ greater concentration. Sorry, I'm not terribly good with words! I have a simple UART program working on my capTouch board specifically. I can input characters and receive and respond to output. For example, I have that really crude switch statement in my main() working. I will upload a picture of the working output via PuTTY. I have actually been following your advice on the last line exactly. I had put together a working UART, then I added the captouch_init() and haptic_init() and that works just fine. When I try to add something, like, say, Haptics_SendWaveform(lra_click); the board quits responding and bricks itself. By numbers, I mean things like : BCSCTL2 |= DIVS_3; Something seems to be wrong with that top half of my code, above the main(). Does that make any more sense? Thank you for your patience! Quote Link to post Share on other sites
Yuri 0 Posted June 3, 2013 Author Share Posted June 3, 2013 many times when u put together code fragments / examples for different systems (uart, cap sense, adc, etc) the conflict will surface because of timer and port io contentions. it is alway wise "stack" code modules one by one when integrating. This is what I think is happening. But I don't know enough about this to write my own from scratch. I have been trying to put this together by slowly adding one more piece of functionality at a time. But when something goes wrong, I don't know why. So I can't offer a fix. I assume it has something to do with my timer, which also messes with the clocks it seems, or whatever BCSCTL2 is. Or something around that area? Quote Link to post Share on other sites
simpleavr 399 Posted June 3, 2013 Share Posted June 3, 2013 @@Yuri In your Haptics_SendWaveform(..), you calls Haptics_OutputWaveform(..) which in turn calls timerdelay(..) in Timer.h The timerdelay(..) function will setup and enable Timer 0 w/ interrupt flag on. This will trigger the Timer_A0_ISR(..) interrupt handler we setup in main.c for handling uart Tx/Rx. I did not examine in detail but I am sure the interrupt handled will be called. I suspect this will cause a indefinite / very slow loop and the system is suspended. I had no luck compiling your code as the CTS/*.h is missing in your repo. I suggest you replace Timer.h functions (both timedelay and sleep) w/ delay_cycles(), or "for loops" to achieve delays. This will avoid contention problem w/ the s/w uart. Both functions (timedelay() and sleep()) just do up counts on CCR0, but on different clocks (ACLK and SMCLK), so may be you can approximate the time w/ delay_cycles(). An alternative would be see if you can adopt h/w uart. I am not very familiar w/ it so you should check if the device / registers has any potential conflict w/ your other modules. Yuri 1 Quote Link to post Share on other sites
Yuri 0 Posted June 3, 2013 Author Share Posted June 3, 2013 Thank you for the advice! I actually just discovered hardware UART, and so far the code for that seems significantly more simple, though there is much less support for it it seems. But I will give your advice a try and report back in a bit. Thank you again! ~Yuri Quote Link to post Share on other sites
Yuri 0 Posted June 3, 2013 Author Share Posted June 3, 2013 New issue to anyone that can help! I have decided to the Hardware UART route, and looked through the examples that exist for that. I do have a working board now, that can simultaneously accept input. EXCEPT : I don't know how to store and analyze input. I see the example goes outside of the main, and echoes what is typed, but where is it exactly stored? And how can I retrieve it? #include "msp430g2553.h" #include "CapTouchBoard.h" #include "Actuator_Waveforms.h" #include "BinaryModes.h" #define SCROLL 250 extern struct Element* modePtr; // Pointer to current mode button pressed extern struct Element* buttonPtr; // Pointer to current effect button pressed struct Element* lastButtonPtr; // Pointer to last effect button pressed unsigned int i; int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT DCOCTL = 0; // Select lowest DCOx and MODx settings BCSCTL1 = CALBC1_8MHZ; // Set DCO DCOCTL = CALDCO_8MHZ; BCSCTL1 |= DIVA_1; // ACLK/(0:1,1:2,2:4,3:8) BCSCTL2 |= DIVS_0; // SMCLK/(0:1,1:2,2:4,3:8) BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO (select SMCLK source) // 8000000 Hz 9600 bps UCA0BR0 = 0x41; UCA0BR1 = 0x03; UCA0MCTL = UCBRS_3 + UCBRF_0; P1SEL = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD P1SEL2 = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD // Set GPIO functions P2SEL &= 0xBF; // P2.0-P2.5 = cap sense, P2.6 = I/O P2SEL2 &= 0xBF; // P2.0-P2.5 = cap sense, P2.6 = I/O P3SEL |= 0x04; // P3.2 = PWM Output // Set GPIO directions P1DIR |= (BUTTON1+BUTTON2+BUTTON3+BUTTON4); // Set P1.0-P1.3 to outputs for colored LEDs P2DIR |= 0x40; // Set P2.6 = Output P3DIR |= (MODE0+MODE1+MODE2+MODE3+MODE4+BIT2+BIT1+BIT0); // Set P3.0-P3.1, P3.3-P3.7 as outputs = LRA/^ERM, EN, M0-M4 // Set GPIO values P1OUT = 0; // Colored LEDs off P2OUT |= 0x40; // Set P2.6 = 1, set load switch to LRA P3OUT = 0x00; // White LEDs off, EN = off // TimerA Setup // Set PWM Frequency, TimerA gives 255 counts at SMCLK frequency TA1CCR0 = 0x00FF; UCA0CTL1 |= UCSSEL_2; // SMCLK UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt CapTouch_Init(); Haptics_Init(); CapTouch_PowerUpSequence(); __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled } // Echo back RXed character, confirm TX buffer is ready first #pragma vector=USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready? UCA0TXBUF = UCA0RXBUF; // TX -> RXed character } #pragma vector=TIMER0_A0_VECTOR __interrupt void ISR_Timer0_A0(void) { TA0CTL &= ~(MC_1); TA0CCTL0 &= ~(CCIE); CapTouch_RandomNumber++; __bic_SR_register_on_exit(LPM0_bits+GIE); } #pragma vector=TIMER1_A1_VECTOR __interrupt void Timer_A1_ISR (void) { TA1CCTL1 &= ~CCIFG; //Clear Interrupt Flag } Quote Link to post Share on other sites
simpleavr 399 Posted June 3, 2013 Share Posted June 3, 2013 Should that be in UCA0RXBUF? Create a volatile variable outside and may be in your main, check on it periodically for non-zero. And process command when non-zero, then set it back to zero to wait for next. static volatile uint8_t cmd=0; // Echo back RXed character, confirm TX buffer is ready first #pragma vector=USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready? // save RXed char before sending it back.. cmd = UCA0RXBUF; UCA0TXBUF = UCA0RXBUF; // TX -> RXed character } And a typical low power application would do a loop to sleep, wait for interrupt to wake up and process command, like so, to save power. replace __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled with while (1) { __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled switch (cmd) { case xxx:.... }//swith }//while Just make sure you add __bic_SR_register(LPM0_bits); as the last line in your __interrupt void USCI0RX_ISR(void) This will allow you to wake up and immediately enter the "switch (cmd)" block upon receiving a character from PC. Yuri 1 Quote Link to post Share on other sites
Yuri 0 Posted June 4, 2013 Author Share Posted June 4, 2013 New Question No matter what UART I seem to attempt to use I have an issue shortly after getting a working I/O system: I cannot run the haptic effects in low power mode. Makes sense as the haptics require physically engaging an actuator. BUT LPM seems to be necessary for interrupts, which make the output work. Is there any way to switch back and forth? Or a way to go through hardware UART without the interrupts? Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.