Jump to content
43oh

Developing software for MSP430!


Recommended Posts

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

Link to post
Share on other sites

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

Link to post
Share on other sites

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.
    }
Link to post
Share on other sites

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.

Link to post
Share on other sites

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

Link to post
Share on other sites

 

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.

Link to post
Share on other sites

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.

Link to post
Share on other sites

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!

Link to post
Share on other sites

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?

Link to post
Share on other sites

@@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.

Link to post
Share on other sites

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

Link to post
Share on other sites

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
}


Link to post
Share on other sites

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.

 

 

 

 

 

 

Link to post
Share on other sites

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?

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...