Jump to content

wilywyrm

Members
  • Content Count

    35
  • Joined

  • Last visited

  • Days Won

    3

wilywyrm last won the day on July 13 2011

wilywyrm had the most liked content!

About wilywyrm

  • Rank
    Advanced Member
  1. I assume you mean the 2452 and the 2553? Basically what you said was right, except the 2553 has a USCI (Universal Serial Communication Interface) so you can talk to a computer through the hardware UART or to other chips via SPI or I2C. For chips without a hardware UART, you have to implement it in software, and instead of a USCI, you would have a USI (Universal Serial Interface) for just SPI and I2C communication. EDIT: At 600+ pages, I personally wouldn't print it because eventually you will miss the Ctrl-F ability of a pdf.
  2. Thanks! Fixed it, and since it looked like there was too much free board space, I added current limiting resistors on the low side.
  3. Hi everyone! Haven't posted here in a long time, so I thought I'd share something I'm working on. Picture this: you and your friends have gotten together for some sweet pen-and-paper roleplaying action. It's the first round of combat, and everyone's getting ready to roll initiative. But then disaster strikes! The family dog has eaten the d20, and you were all sharing the same set of dice because YOUR FRIENDS ARE ALL TOO CHEAP TO BUY THEIR OWN! The obvious solution is to buy sets for them and give it to them for Christmas or something, but there's no fun in that. Cue MSPDice, a fully fledged dice set in a compact 2"x2" frame. The MCU used will be the MSP430G2231 (DIP and TSSOP footprints both on board), which will push out the results of a d4, d6, d8, d10, d12, d20, or d% roll to a 4-digit common anode 7-segment display through a 74HC595 shift register. I have tried to break out the pins of the MSP430 so that it fits the launchpad's spacing (4.5cm, is it?), but haven't really checked it. at 1.8". Thanks Rob! I'm using mspgcc and mspdebug for programming, KiCAD for board design, and GerbV to look at the gerbers on a linux box. You know, the whoooole open-source enchilada. #include #include //#define DOUT BIT6 //#define SCLK BIT5 // Data Output and System clock are still P1.6 and 1.5, though. That's the hardware USI #define LATP BIT0 // the Latch Pin on the 595, pin 0 (port 1) #define EN BIT7 // the pin connected to the 595's Output ENable 7 (port 1) // the pins the P-FETS are hooked up to (port 1) const unsigned char digit[4] = {BIT1, BIT2, BIT3, BIT4}; volatile unsigned char a = 0; /*#define DIGIT1 BIT1 #define DIGIT2 BIT2 #define DIGIT3 BIT3 #define DIGIT4 BIT4*/ #define DIGITS BIT1+BIT2+BIT3+BIT4 // for convenience of addressing #define NEXT BIT6 // the pin hooked up to the NEXT button, pin 6 (port 2) #define PREV BIT7 // " " 7 (port 2) // 595 hooked up Q0-a, Q1-b,... Q7-DP. Inverted because 595 is sinking current, and bit order is DP, g, f,... a. const unsigned char digitMask[11] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xA1}; // last digit is d, as in d20. //volatile unsigned char show = 0; // brotip: short is NOT a short. It's 16 bits. volatile unsigned char i = 0; volatile unsigned char dieType = 6; // remember the kind of dice we last used! int main(void) { WDTCTL = WDTPW + WDTHOLD; // stop WD timer BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO IFG1 &= ~OFIFG; // Clear OSCFault flag __bis_SR_register(SCG1 + SCG0); // Stop DCO BCSCTL2 = SELM_2 + SELS; // MCLK = VLO, SMCLK = VLO // initialize all the pins and their resistors P1DIR |= 0xFF; // I was going to add all the pin values, but they're all outputs. P1SEL = 0x00; // All pins on Port 1 are either GPIO or the modules they're connected to don't care. P2SEL = 0x00; // select GPIO functions P2DIR = 0x00; // make the XIN/XOUT pins GPIO Inputs rather than CLK inputs P2REN = NEXT + PREV; // enable internal pull resistors on button inputs P2IES = 0x00; // trigger an interrupt for the button pins on a low-to-high transition. Change this to 0xFF in the interrupt routine because we need to see when they stop pressing the button. P1OUT |= LATP + DIGITS + EN; // make LATP, DIGITx, EN high P2OUT = 0x00; // make the button input resistors pull down P2IE = 0xFF; // enable the interrupts, but hey, TODO: code the interrupt HANDLERS... P1OUT &= ~EN; // enable 595 output (by making the EN pin low) USICTL0 |= USIPE6 + USIPE5 + USIMST + USIOE; // enable SPI out, SPI SCLK, SPI Master, and data output USICTL1 |= USICKPH + USIIE; // Counter interrupt, flag remains set USICKCTL = USIDIV_1 + USISSEL_1; // divide clock source by 2 to get the clock for USI and select SMCLK as the source for USI clock // USI will offset the byte we're shifting out by 3 bits if you don't divide ACLK by 2, so 1 -> 3 and 6 -> 11? Strange. Probably a startup problem. USISRL = 0xFF; // start up cleared USICTL0 &= ~USISWRST; // allow the USI to function CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 3000; // timer is on ACLK/2 (7kHz, 2000/(7000 cycles/s * 1s) ~= a period of .286 s.) TACTL = TASSEL_1 + MC_1 + ID_1; // ACLK, Up mode, div ACLK by 2, ~= 7kHz // TimerA doesn't like to have TASSEL_2 (SMCLK) set, so we just stuck it into ACLK, which comes from the same source (ACLK) __bis_SR_register(LPM3_bits + GIE); // Enter LPM0 w/ interrupt } // Timer A0 interrupt service routine //#pragma vector=TIMERA0_VECTOR //__interrupt void Timer_A (void) // so much for that, thanks a lot mspgcc interrupt(TIMERA0_VECTOR) Timer_A(void) { P1OUT &= ~LATP; // latch goes low USISRL = digitMask[i]; // write the byte to the USI i++; i %= 11; P1OUT |= DIGITS; USICNT = 8; // USI shifts out 8 bits (that byte we just entered) P1OUT &= ~digit[a]; a++; a %= 4; P1OUT |= LATP; // latch goes high and previous instructions give time for USI to shift out } Typical usage should go like this: [*:erp26ks3]Type of die to roll (dX) [*:erp26ks3]Number of dice to roll (YdX) [*:erp26ks3]Randomization display (Raw random output is pushed to the display) [*:erp26ks3]Result display I've put up this post mainly because it forces me to have a clear picture of how everything will fit together, but if anyone has any suggestions, say something before I send this design off to Seeed at the end of the week! This needs to be as awesome as possible so my friends stop borrowing my dice! Most recent edit: R4r3. Added a DIP footprint for the 74HC595. Every major component but the buttons can now be a through-hole part. (Oh, and I did finish that robot arm from earlier. One of these days I'm going to clean it up and put up the board design on github, along with the dice board, but Right now the code's disgraceful.) mspDice.pdf mspDice.zip
  4. Hi again guys, I got the UART to work thanks to Rickta and pabigot but now am having trouble generating a PWM signal to control my servos. What I'm trying to do is use TA1CCR0 and the timer overflow interrupt to generate a square wave. Instead of CCR0 determining the period length like usual, I'm trying to use a clock of 3MHz (DCO 12MHz / 4) to get a overflow every 65536/3000000 = ~21.8ms for period length and use CCR0 to take care of pulse width. CCR0 should be serviced twice every period, once to start the pulse and another to end the pulse. Every time the CCR0 interrupt is serviced, P2.0 is toggled and ONLY if CCR0 is at its original point, it will be incremented by an amount corresponding to the pulse length. Here it is 4500 cycles, which is equal to 1.5ms. While the code IS giving me a signal, 1.5ms should be center for the servo, but it's going to the FAR, FAR left instead. We're talking past what seems to be its normal operating limit. I'm planning on using this general process with the remaining 5 CCRs, so that's why you see an array of 6 positions and offsets. Offsets are there to spread out the current spike accompanying every pulse start, and pulses are so small that there should be no more than one at a time. This code was the only relevant part snipped from a larger file I have, but it compiles and gives me the same issue. #include #include #include #include #define MCLK_FREQ 12000000UL /* run @12MHz */ void initMCLK(); inline void initSMCLK(); //servos are: base rotater, base hinge, elbow, wrist, gripper, unused const unsigned int offset[6] = {0, 10000, 20000, 30000, 40000, 50000}; // offsets to avoid simultaneous current spikes unsigned int position[6] = {4500, 4500, 4500, 4500, 4500, 4500}; // all set to center initially // we use this to generate pulses for the servos void initTimerA(); // reset CCRs to their original pulse start points void resetPulses(); inline void resetTimerIFG(unsigned int numTimer); int main(void) { WDTCTL = WDTPW | WDTHOLD; /* Disable watchdog */ initMCLK(); // for the CPU initSMCLK(); // for great justice initTimerA(); __bis_SR_register(GIE); while(1); return 0; } void initMCLK() { // Use 12MHz DCO factory calibration DCOCTL = 0; BCSCTL1 = CALBC1_12MHZ; DCOCTL = CALDCO_12MHZ; } inline void initSMCLK() { BCSCTL2 |= DIVS_2; // make SMCLK = DCOCLK / 4 = 3MHz } void initTimerA() { P2DIR |= BIT0; TA1CCTL0 = CCIE; resetPulses(); TA1CTL = TASSEL_2 + ID_0 + MC_2 + TAIE; // SMCLK as Timer_A's CLK, DIV that clock by 1, continuous mode, enable interrupts } void resetPulses() { TA1CCR0 = offset[3]; // PWM pulse width } interrupt(TIMER1_A0_VECTOR) TA1CCR0_ISR(void) { unsigned int time = TAR; P2OUT ^= BIT0; // toggle P2.0 on if(time == offset[3]) { // if we just hit pulse start TA1CCR0 += position[3]; // redefine CCR0 as pulse end, it will toggle P2.0 off next time } } interrupt(TIMER1_A1_VECTOR) TA1(void) { // handles the overflow interrupt resetTimerIFG(1); // clear all the flags } inline void resetTimerIFG(unsigned int numTimer) // cause, come on. { if(numTimer) // if numTimer == 1, anything besides 0 is treated as a true, so if(not 0) while(TA1IV); else while(TA0IV); // see above } Unfortunately, I don't have access to an oscilloscope, so I can't actually check what the pulse length I'm getting out is. I DO however have a working 555 servo tester. It outputs a maximum averaged voltage of ~0.4V when the servo is at the far left as opposed to the 1.8V I'm getting from my MSP430. I'd really appreciate any help I could get, especially if it turns out that what I'm doing with moving the CCRs in the middle of the period is wrong.
  5. They got discontinued after March last year. I guess not enough big manufacturers wanted them anymore. NXP still makes them, though, and I think nobody's link shows what I'm talking about.
  6. wilywyrm

    TI Sample Program

    To be honest, that makes it sound like TI knew all this and still singled him out...
  7. Today was... a learning experience. I had wanted to use an external crystal to provide a 16MHz MCLK and spent all day trying to figure how, but it looks like the G2553 doesn't even have the capability to use an oscillator above 50kHz! I hope they provide that in a later G-series generation, but in the meantime, I'll have to use the DCO like in Rick's code. Plan is now a 1MHz MCLK, 500kHz SMCLK for the controller's SPI bus, and 32.768kHz for the UART. All the advice and links you gave will definitely help with fully understanding UART functionality, but for now I'll leave good enough alone and hope I don't break anything. Scheduled deadline's in a week. By the way, what license is the code under? Here's Rick's code modified to conform to boring, old C. /** * main.c - swserial/timerserial/usciserial Serial Asynch test driver. * * To test: use putty and connect to /dev/ttyACM0 at 9600 Baud * */ #include #include #include #include "serial.h" #define MCLK_FREQ 16000000UL /* run @16MHz */ /** * typedef Serial - start of a simple serial wrapper class */ //typedef struct { /** * begin() - initialize serial port, sets registers, port direction, and * alternative port features as required by implementing serial routines. * Depending on the implementing method, you may not be able to use * arbitrary rx/tx pins the software only implementation is the only * version capable of using any arbitrary pin. * * baudRate - bits/sec default: 9600 * rxPin - receive pin default: 1 (P1.1) ( g2553 defaults ) * txPin - transmit pin default: 2 (P1.2) */ /* static void begin(uint32_t baud = 9600, int rxPin = 1, int txPin = 2) { init_serial(1 << txPin, 1 << rxPin, MCLK_FREQ / baud, (MCLK_FREQ / baud) >> 8); } */ /** * puts - writes the string s to the serial output stream without a trailing * newline character. Note: this differs from the ISO standard puts() * function which appends a newline character. ` */ /* static void puts(register const char *s) { while(*s) { putchar(*s++); } } } serial_t; static serial_t Serial; */ //void begin(uint32_t baud = 9600, int rxPin = 1, int txPin = 2) { void begin(uint32_t baud, int rxPin, int txPin); //void puts(register const char *s) { void putS(const char *s); //static void initMCLK() void initMCLK() { #ifdef __MSP430FR5739 CSCTL0_H = 0xA5; // CS_KEY CSCTL1 |= DCOFSEL0 + DCOFSEL1; // Set max. DCO setting CSCTL2 = SELA_3 + SELS_3 + SELM_3; // set ACLK = MCLK = DCO CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0; // set all dividers #else // Use 16MHz DCO factory calibration DCOCTL = 0; BCSCTL1 = CALBC1_16MHZ; DCOCTL = CALDCO_16MHZ; #endif } int main(void) { WDTCTL = WDTPW | WDTHOLD; /* Disable watchdog */ initMCLK(); // configure serial device using defaults //Serial.begin(9600); begin(9600, 1, 2); //__eint(); // we enable interrupts after user setup() to give them a chance to customize // if you are using an FTDI or other reasonable USB-serial chip you can output // serial data at reset. If you want to use the Launchpad /dev/ttyACM0 you have // to wait for a request before spewing. int c; int nCharCnt = 0; while(1){ c = getchar(); // do some minimum line control to handle backspace if ( c != 127 ) { putchar(c); nCharCnt++; } else { if (nCharCnt > 0) { putchar(c); --nCharCnt; } } // append newline on CR if ( c == '\r' ) { //Serial.puts("\n# "); putS("\n# "); nCharCnt = 0; } // restart processor on CTRL-D if ( c == 0x04 /*CTRL-D*/ ) { WDTCTL = WDTHOLD; // restart by setting the WDTCTL without a password } } return 0; } /** * begin() - initialize serial port, sets registers, port direction, and * alternative port features as required by implementing serial routines. * Depending on the implementing method, you may not be able to use * arbitrary rx/tx pins the software only implementation is the only * version capable of using any arbitrary pin. * * baudRate - bits/sec default: 9600 * rxPin - receive pin default: 1 (P1.1) ( g2553 defaults ) * txPin - transmit pin default: 2 (P1.2) */ //static void begin(uint32_t baud = 9600, int rxPin = 1, int txPin = 2) { void begin(uint32_t baud, int rxPin, int txPin) { init_serial(1 << txPin, 1 << rxPin, MCLK_FREQ / baud, (MCLK_FREQ / baud) >> 8); } /** * putS - writes the string s to the serial output stream without a trailing * newline character. Note: this differs from the ISO standard puts() * function which appends a newline character. */ //static void puts(register const char *s) { void putS(const char *s) { while(*s) putchar(*s++); } Makefile: CC=msp430-gcc CFLAGS=-Os -Wall -g -mmcu=msp430g2553 usci_serial.c #no, that's not really the proper way to do it, but it works! OBJS=main.o all: $(OBJS) $(CC) $(CFLAGS) -o main.elf $(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< clean: rm -fr main.elf $(OBJS)
  8. pabigot, thanks for the suggestion. I need to try that tomorrow. Rick, thank you SO much for the code. I'm actually getting output now! I did have to modify your code a little and take out some C++ stuff since mspgcc doesn't want to compile the cpp file. I'll post it tomorrow for reference, but it does work and I understand it for the most part. The (comparatively small) trouble now is that I don't get this modulation business. Could you explain the UCA0BR1 register? The datasheet goes a little over my head on the first read, and mainly I want to know how to adjust the registers for different clock speeds. The USCI does NOT like me simply redefining MCLK_FREQ to 32768 and choosing ACLK. Again, thanks everyone. I've gotten more done today than the last week because of your help.
  9. Thanks for the help, guys! Still don't have it fixed or really know why, though. Does the code without the change output a single 'a'? I'm using a Rev 1.4 launchpad right now, but I do have a 1.5 also. I don't think the problem is with the jumpers because it works with TI's unmodified code example perfectly. Sorry for not being clear, and "interrupt-based" meant hardware USCI (USCIAB0RX_VECTOR, USCIAB0TX_VECTOR, all that good stuff). If hitting the port with a unsolicited continuous stream of 'a's will kill the port, how do I not kill it without sending something first? The goal eventually is to be able to control the arm through a wireless PS2 controller, but I'll need the msp to give me continuous positioning output to my PC before I can hope to even get hardwired servo control right.
  10. I'm doing a robot arm project for a competition at my school, and I'm having real trouble with getting the g2553 hardware UART to work. For the life of me, I can't figure out why it's not printing anything at all. I compiled the TI code example that I'm modifying and it works just fine on my Linux box with Cutecom, but when I make transmission not interrupt-based, I get nothing! :x The functions I have in there were what I planned to use with a timer to send strings after a TimerA interrupt, but eventually I stripped it down to just writing to the TX buffer. Still nothing. Shouldn't it give me an 'a"? //****************************************************************************** // MSP430G2xx3 Demo - USCI_A0, Ultra-Low Pwr UART 9600 String, 32kHz ACLK // // Description: This program demonstrates a full-duplex 9600-baud UART using // USCI_A0 and a 32kHz crystal. The program will wait in LPM3, and will // respond to a received 'u' character using 8N1 protocol. The response will // be the string 'Hello World'. // ACLK = BRCLK = LFXT1 = 32768Hz, MCLK = SMCLK = DCO ~1.2MHz // Baud rate divider with 32768Hz XTAL @9600 = 32768Hz/9600 = 3.41 //* An external watch crystal is required on XIN XOUT for ACLK *// //****************************************************************************** #include #include void writeChar(char aChar); void writeWord(char* word); void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1DIR = 0xFF; // All P1.x outputs P1OUT = 0; // All P1.x reset P2DIR = 0xFF; // All P2.x outputs P2OUT = 0; // All P2.x reset P1SEL = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD P1SEL2 = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD P3DIR = 0xFF; // All P3.x outputs P3OUT = 0; // All P3.x reset //CCTL0 = CCIE; // CCR0 interrupt enabled //CCR0 = 50000; //TACTL = TASSEL_1 + MC_2 + TAIE; // ACLK, contmode, enable timer interrupt UCA0CTL1 |= UCSWRST; // Put state machine in reset UCA0CTL1 |= UCSSEL_1; // CLK = ACLK UCA0BR0 = 0x03; // 32kHz/9600 = 3.41 UCA0BR1 = 0x00; // UCA0MCTL = UCBRS1 + UCBRS0; // Modulation UCBRSx = 3 //UC0IE |= UCA0RXIE | UCA0TXIE; UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** UCA0TXBUF = 'a'; __bis_SR_register(GIE); } void writeChar(char aChar) { while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready? UCA0TXBUF = aChar; // TX next character //IFG2 &= ~UCA0TXIFG; } void writeWord(char word[]) { while(*word) //for(unsigned int i = 0; i < sizeof word - 1; i++) writeChar(*(word++)); } Here's the makefile, if it helps. I think the only changes are that the mcu flag was set to msp430g2553 to make Uniarch happy and the version of C to c99. CC=msp430-gcc CFLAGS=-Os -Wall -g -mmcu=msp430g2553 -std=c99 OBJS=main.o all: $(OBJS) $(CC) $(CFLAGS) -o main.elf $(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< clean: rm -fr main.elf $(OBJS) I've been stuck on this for days and would be tremendously grateful to anyone who could help.
  11. It shouldn't. I imagine they reserved the Launchpad chips from some batch earlier in the year. For what it's worth, I ordered mine on the 22nd and got it today. It's a 1.5!
  12. wilywyrm

    MSP430ware

    I have to say, I don't think typing all that out will save anyone any time.
  13. Well, that's the thing. I think it cost them so much to ship those boxes that they changed all their deals to "free shipping on orders over $50". I may have single-handedly killed that for you guys. :cry:
  14. All this is hilarious and so true. I once ordered from Arrow. They packed the whopping 2 ATMegas I ordered in a full tray designed for 64 chips and wrapped it all in an outrageously cushioned box about 3 feet wide. And don't get me started on Element14. Last year they had a free shipping promotion and I took advantage of it to put in a full E12 set of through-hole and SMD resistors from 10 Ohms to 1M Ohms in one of mine. Individually. Big mistake. They packed each value of resistor in its own padded paper envelope. All 120 of them. That took up so much space they had to send two 6 feet long boxes. The UPS guy has never lived this down. As much as I love these companies for their promotions and... dedication to protecting their components, there's a point where you wonder if they profited from your order.
×
×
  • Create New...