Jump to content


  • Content Count

  • Joined

  • Last visited

Reputation Activity

  1. Like
    dacoffey reacted to abecedarian in Acrylic dragon   
    video here: http://flic.kr/p/drRYyM
  2. Like
    dacoffey reacted to garyamort in Turning a Launchpad into a poor mans IOIO   
    I've been working on turning a Launchpad into a poor mans IOIO. The latest version of the IOIO adds support for connecting from the computer to the board using a bluetooth serial connection. This means if I copy the underlying protocol[or at least as much as I need] - I can then emulate the IOIO for my real goal[see below].
    I'm just in the beginning phase right now, my initial goal is to get it working so I can use the IOIO protocol to turn on and off the 2 LED's on board. IE just cloning the Digital Output functionality and only on 2 pins.
    I'm hoping to finish that this weekend. Right now I just have the initial skeleton of combining the TI example code for 9600 baud uart and some basic IOIO headers.
    Once I get the 2 pins working, the next step is to allow for access to all 10 available pins on the MSP430G2553 [there is 1 and a half ports available, but 2 pins have to be used form the serial connection].
    This is where I figured I'd ask if there is a standard way of doing things as I'm re-learning C as I go along.
    A command will consist of a few bytes of data:
    The command byte, such as I beleive 6 and 7 for digital output. 6 to turn a pin into a digital output, 7 to change the value being sent out. Following the command is the "pin number" - where pin number is defined by where they come out on the board, not where they are on the launchpad.
    For my purposes:
    Pin 1: Port 1.0
    Pin 2: Port 1.3
    Pin 3: Port 1.4
    Pin 4: Port 1.5
    Pin 5: Port 1.6
    Pin 6: Port 1.7
    Pin 7: Port 1.0
    Pin 8: Port 2.1
    Pin 9: Port 2.2
    Pin 10: Port 2.3
    Pin 11: Port 2.4
    For the simple case of:
    Pins 1 and 5[1.0 and 1.6] I can use a simple switch/case to send the correct BIT to P1SEL
    However, to expand it to all 10 pins, I would rather not have a humungous SWITCH/CASE. It would be better to have a mapping of pins to their appropriate bit, port address, and value. Something like:
    PINDEF selectedPin = pinmap[1];
    selectedPin->port |= selectedPin->digitalOutBit;
    selectedPin->iovalue |= selectedPin->digitalOn;
    While I understand easily how to do the digitalOutBit and digitalOn - they are just values. The question is how to I assign a variable[selectedPin->port] so that it can be used in the same manner as P1SEL ?
    Thanks for any feedback.
    Sidenote: my /goal/ is yet another oscilliscope. However, since my strongest skillset is website engineering[php/HTML/CSS/Javascript] - my preference is to make the scope as a Javascript application run from the web browser. I can hack enough Python to use the Python serial and websocket library to provide access to the com port from the web browser - so with that in place it makes it a lot faster for me to write IOIO apps which will also be usable with a Launchpad by using Javascript.
    For added fun, I want to setup a PHP library so that I can have the launchpad display the number of users on a website via an LED bargraph and maybe have it play a sound when different "goals" are met.
    NOTE: I found I had to hunt through the project settings in CCS to find and enable the "relaxed-ansi" option in order to get the "packed" structures to work.
  3. Like
    dacoffey reacted to bluehash in Latest Awarded Members   
    List of awards here. Feel free to suggest a few.
  4. Like
    dacoffey reacted to bluehash in Welcome!   
    Welcome everyone!
    Looks everything went well from phpbb3 to ipboard..even the "Thanks!" statistics. The old links will redirect to this board. We also have a new url .. forum.43oh.com, which I was dying to change.
    Thanks to TeraByte from invisionbyte.net/. He has been very prompt and helpful during these two days. If you know anyone who needs a board converted to ipboard, he's the perfect guy.
    So.. there are still going to be a few spammers for the first week as I tweek settings.
    Also, please list all bugs below:

    1.Internal links in a post, like: http://forum.43oh.com/topic/1786-group-buy-index/ Links get redirected to the main ipb forum. 2. Rename "Like This!" to "Thanks!"
    Happy Halloween!
  5. Like
    dacoffey reacted to RobG in RGB Globe   
    I just came across this project and it is so awesome, I have to make one like that for my kids
    Unlike SolderLab guys, I will not use wires, I will use PCBs as a frame.
    Here are my few initial ideas:
    1. Create 1" x 2" boards, contacts on both ends, 5050 or 5mm LEDs, chips on the bottom.
    2. Create circular boards out of 4" boards, 1/4, 1/6, or 1/8 circle. 5mm LEDs.
    I think I will go for 2nd option since it's easier to assemble.
    Each segment will have 16 LEDs, 6 chips, few caps, and possibly place for MCU and IR detector, so no additional boards will be required.
    Also, I will use TLC series chips because they have constant current outputs, more current, less resistors, less soldering.
    BTW, SolderLabs' GlobeSimulator software is available for free!

  6. Like
    dacoffey reacted to energia in Simple one-button combination lock   
    You could look into interrupt driven logic. This could be applied to the unlocking as well as the learning.
    I haven't given this much bought but for the unlocking you could use combination of attachInterrupt() and mills(). The msp430 unfortunately does not have state change interrupt so you will have to flip RISING/FALLING interrupt inside the ISR by detaching and then attaching on the opposite edge. The counter for how long the button was pressed can be updated using mills() inside the ISR...
    You could use the same logic for recording while in learning mode.
  7. Like
    dacoffey reacted to bobnova in Simple one-button combination lock   
    One of my first MSP430 projects here, this is a (very) simple one-button combination lock. At the moment it's just using the launchpad's single button and the two LEDs for lock status. You'd need to figure out what you were locking or unlocking and add code for that obviously.
    It's all delay based, so it assumes you aren't doing anything overly crucial other than minding the button, or at least that the other tasks (if any) can be put on hold while the button is being used.
    I'm sure there are "better" ways to do it, but this seems to work so far!

    int counter; byte wiggleRoom = 25; //the amount + or - of the exact correct push length to pass a lock level, measured in 10ms steps. byte lockLevel = 1; //Stores what button press the lock is on boolean open = false; boolean buttonState; int test1 = 100; //Number of 10ms steps the button should be held down for the first time int test2 = 50; //Same, for press two. int test3 = 100; //And press 3. So for this setup, we press for 1s, let up, press for 0.5s, let up, press for 1s void setup(){ pinMode(P1_0, OUTPUT); pinMode(P1_6, OUTPUT); pinMode(P1_3, INPUT_PULLUP); } void loop(){ if (!open){ // normal state, red LED on, green LED off. digitalWrite(P1_0, HIGH); //In this section you would shut the lock, whatever it was. digitalWrite(P1_6, LOW); } else{ digitalWrite(P1_6, HIGH); //Open the lock digitalWrite(P1_0, LOW); delay(3000); //Wait a bit. lockLevel = 1; open = false; //Set the lock to close next pass through the code. //Might not be a bad idea to close the lock here too, really. //That would prevent the button being held down keeping the lock open. } buttonState = digitalRead(P1_3); if (!buttonState){ //Button is pushed counter = 0; //reset the counter, this is crucial. while (!buttonState){ //As long as the button is held down, this cycles. counter++; delay(10); //10ms per cycle, record the number of cycles. buttonState = digitalRead(P1_3); //We do need to get out eventually, when the button opens } switch (lockLevel){ //Now that we have a press duration, we need to find what level the lock is on case 1: //If it's the first press, we start here. if (counter >= test1 - wiggleRoom && counter <=test1 + wiggleRoom){ lockLevel = 2; //Adjust wiggleRoom to be the number of 10ms steps you want for wiggle room. counter = 0; //Right now we get +/- 250ms. digitalWrite(P1_6, HIGH); //Flash the green LED if the push was successful. Mostly for debugging. delay(50); digitalWrite(P1_6, LOW); } else{ lockLevel = 1; //If the push is the wrong length, start over. counter = 0; } break; case 2: if (counter >= test2 - wiggleRoom && counter <=test2 + wiggleRoom){ //Second push, same deal. lockLevel = 3; counter = 0; digitalWrite(P1_6, HIGH); delay(50); digitalWrite(P1_6, LOW); } else{ lockLevel = 1; //If the push is the wrong length, start over from push 1. counter = 0; } break; case 3: if (counter >= test3 - wiggleRoom && counter <=test3 + wiggleRoom){ open = true; //Third correct push opens the lock. counter = 0; } else{ lockLevel = 1; counter = 0; } break; } } }
    The next thing I'm inclined to work on is some learning, so that it remembers how long you hold the buttons down and adjusts the official "correct" number to match over time. The other thought is to time the delay between presses and use that as part of the combination, it would complicate the code fairly significantly but also increase security for a given time spent with the button.
    I got the idea while contemplating vehicle security, my thought was to re-use a dash button as the input button and control the fuel pump relay (that wouldn't turn off after three seconds!). That would give you totally invisible anti-theft in theory.
    I can't recommend it exactly, depending on how it's wired a dead MSP430 may render the vehicle suddenly stopped, not ideal!
  8. Like
    dacoffey reacted to larryfraz in 2-osc PWM Midi Synth   
    I put together a 2 oscillator PWM MIDI synthesizer based on NatureTM's (thanks!) 'simple synth'. No DAC is needed. The second oscillator can be detuned and has a blend control, both accessed via midi cc's. A clip of it, and the code, are on my site at the perspectivesound blog. I haven't added adsr, I may add some more features soon.
  9. Like
    dacoffey reacted to Nytblade in Internet-connected MSP430 Experimenter Board   
    The maximum size of a DHCP packet is 576 bytes per the RFC.
    However, that is not really the problem. I made my code abstract so that the user just passes a pointer to some block of memory and my functions copy the data to the wiznet buffer and flush it out over the internet. I did it this way so that if I wanted to switch to wifi or a different ethernet chip in the future, I would not have to change the entire codebase. I would just add another driver function for the new device.
    If you compare this to the Arduino W5100 ethernet and dhcp library, what they are doing is using the wiznet onboard memory buffers directly, to save memory. Of course then their code is littered with all sorts of wiznet-specific hackery. That is not really something I wanted since mine is supposed to be a more general "operating system" that I wouldn't have to keep rewriting. Their code does use less memory though.
    In summary, my code works like this: 1) User allocates memory on stack or heap 2) user passes buffer pointer and size to networking functions 3) networking functions hide all the ugly wiznet details and push the data out.
    Since I have written my own heap memory allocator, external memory chips should not be too difficult for me to add support for.
    To actually answer your question: The amount of free memory should be at least the size of the data the user wants to send. (although there is nothing preventing them from calling send more than once if it is some graphic for a webserver or something like that)
  10. Like
    dacoffey reacted to bluehash in [ REMINDER ] Please Thank Members that help you out.   
    Hello everyone,
    There has been alot of good questions going on in the past few weeks - accompanied with very good discussions. One way you can show your appreciation is by using the "Thanks" or "Thumbs up " button on the top right. It may be hard to notice but a screenshot always helps:

    Use it if you have received something useful from a member. It takes time to write those posts and code. Consider it as karma, that's as good as it can get. :mrgreen:
    Thanks everyone..and wish you a happy new year.
  11. Like
    dacoffey reacted to Nytblade in Internet-connected MSP430 Experimenter Board   
    I now have a working DHCP client I wrote on the MSP430, full UDP/TCP support, and some example code with a Daytime Client and Echo Server. I am using the MSP430F5438 Experimenter Board to develop this code.
    Here is an detailed blog post on my progress with the BSD-licensed code you can download:
    http://www.cashdollar.org/2012/10/17/dh ... completed/
    This is using the Wiznet W5200 ethernet chip which is also used in the 43oh Ethernet Boosterpack, however my code uses too much RAM to work with the Launchpad. I probably could clean up my code and fit it on FRAM Fraunchpad Experimenter Board but it uses a different pinout than the Launchpad, so it isn't compatible with the Boosterpack.
    I think I am going to take a break from this project for a while and play around with the Stellaris Launchpad which I just received.
  12. Like
    dacoffey reacted to spirilis in A simple shell, step by step [eZ430 - RF5000]   
    Not bad! I think the main issue some will have is handling the writing of characters/etc. inside the ISR, it's usually preferred to stay inside the ISR as little as possible...
    Here's an alternative library I wrote: https://github.com/spirilis/mspuartcli
    It's written for the value-line G2553 though, but I'd imagine it'll work on any USCI_A capable processor... specific UART timing stuff has to be edited inside uartcli.c's uartcli_begin() function but the rest is standard USCI_A operations.
    It lets you define commands as an array of strings (in Flash/ROM too, using const char *) and the uartcli_token_cmd() function returns -1 if the command is not present or an index from 0 to (string array size minus 1) which you can then test with a big switch() section. And then you can request the different arguments by ID.
    There's a short/non-useful main.c in the git repository but here's a ..... somewhat LONG example main.c that utilizes it to blink LEDs (lets you mess with a VLOCLK-driven TimerA):

    /* UARTCLI-based demo application providing a CLI for switching the LEDs, reading the VLOCLK TimerA * tweaking the rate of TimerA in relation to VLOCLK. */ #include #include #include #include "uartcli.h" const char *cmdlist[] = {"led", "vlo", "vloirq", "vlorate", "help", NULL}; /* VLOCLK timer user status */ volatile char vlostat; #define VLO_ENABLED 0x01 #define VLO_IRQ_MARK 0x02 /* Function prototypes */ void VLO_TimerA_switch(char); char VLO_TimerA_enabled(); void VLO_TimerA_set_divider(char); char VLO_TimerA_get_divider(); void VLO_TimerA_overflow_mark(char); char VLO_TimerA_overflow_mark_enabled(); void VLO_TimerA_overflow_check(); void command_processor(); /* Main loop */ int main() { char cmd[64]; WDTCTL = WDTPW | WDTHOLD; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; BCSCTL2 = DIVS_2; // SMCLK = MCLK/4 BCSCTL3 = LFXT1S_2; // ACLK = VLOCLK/1 while (BCSCTL3 & LFXT1OF) ; /* Global initialization */ vlostat = 0x00; P1OUT &= ~(BIT0 | BIT6); // LEDs switched off, enabled as GPIO outputs P1DIR |= (BIT0 | BIT6); // P1SEL &= ~(BIT0 | BIT6); // P1SEL2 &= ~(BIT0 | BIT6); // // Let'er rip uartcli_begin(cmd, 32); uartcli_println_str("vlotoy MSP430 Command Line Interface"); uartcli_println_str("OK"); while (1) { if (uartcli_available()) { command_processor(); uartcli_clear(); // Tell UART code we're done processing the last cmd, and it can accept new input. // Otherwise it will quite literally ignore every character coming in. uartcli_println_str("OK"); } if (vlostat & VLO_IRQ_MARK) { uartcli_println_str("VLOCLK MARK"); vlostat &= ~VLO_IRQ_MARK; } LPM0; } } void VLO_TimerA_switch(char onoff) { if (onoff) { TACTL = (TACTL & ID_3) | // Save previous value of input divider (TACTL & TAIE) | // Save previous value of TAIE, but clear TAIFG TASSEL_1 | // ACLK (VLOCLK) MC_2 | // Count continuously TACLR; // Clear timer vlostat |= VLO_ENABLED; } else { TACTL &= ~MC_3; // Stop mode vlostat &= ~VLO_ENABLED; } } char VLO_TimerA_enabled() { if ( (TACTL & MC_3) != 0x00 ) return 1; return 0; } void VLO_TimerA_set_divider(char divider) { switch(divider) { case 1: TACTL = (TACTL & ~ID_3); break; case 2: TACTL = (TACTL & ~ID_3) | ID_1; break; case 4: TACTL = (TACTL & ~ID_3) | ID_2; break; case 8: TACTL |= ID_3; break; } } char VLO_TimerA_get_divider() { switch (TACTL & ID_3) { case ID_0: return 1; break; case ID_1: return 2; break; case ID_2: return 4; break; case ID_3: return 8; break; } return 0; // should never reach this far } void VLO_TimerA_overflow_mark(char onoff) { if (onoff) { TACTL &= ~TAIFG; TACTL |= TAIE; } else { TACTL &= ~(TAIFG | TAIE); } } char VLO_TimerA_overflow_mark_enabled() { if (TACTL & TAIE) return 1; return 0; } void VLO_TimerA_overflow_check() { if (vlostat & VLO_IRQ_MARK) { uartcli_print_str("VLOCLK mark"); vlostat &= ~VLO_IRQ_MARK; } } /* TimerA overflow interrupt */ #pragma vector=TIMER0_A1_VECTOR __interrupt void TA_ISR(void) { TACTL &= ~TAIFG; vlostat |= VLO_IRQ_MARK; __bic_SR_register_on_exit(LPM4_bits); } /* Command processor */ // const char *cmdlist[] = {"led", "vlo", "vloirq", "vlorate", "help", NULL}; void command_processor() { int cmdidx, i=0; char buf[32]; uartcli_token_begin(); cmdidx = uartcli_token_cmd(cmdlist); switch (cmdidx) { case 0: // LED if (uartcli_token_arg(1, buf, 32) != NULL) { i = 0; if (!strcmp(buf, "on")) { P1OUT |= BIT0; // Enable red LED uartcli_println_str("led: switched on"); i = 1; } if (!strcmp(buf, "off")) { P1OUT &= ~BIT0; // Disable red LED uartcli_println_str("led: switched off"); i = 1; } if (!i) { uartcli_println_str("Syntax: led "); } } else { // Without any arguments, we assume the user is querying the status. if (P1OUT & BIT0) { uartcli_println_str("led: on"); } else { uartcli_println_str("led: off"); } } break; case 1: // VLO enable/disable if (uartcli_token_arg(1, buf, 32) != NULL) { if (!strcmp(buf, "on")) { VLO_TimerA_switch(1); uartcli_print_str("VLOCLK switched on, timer divider = "); uartcli_println_int(VLO_TimerA_get_divider()); } if (!strcmp(buf, "off")) { VLO_TimerA_switch(0); uartcli_println_str("VLOCLK switched off"); } } else { // Display VLO TimerA on/off status if (VLO_TimerA_enabled()) { uartcli_print_str("VLOCLK Timer enabled; current value: "); uartcli_println_uint(TAR); } else { uartcli_println_str("VLOCLK Timer disabled"); } } break; case 2: // VLOIRQ (overflow mark) enable/disable if (uartcli_token_arg(1, buf, 32) != NULL) { if (!strcmp(buf, "on")) { VLO_TimerA_overflow_mark(1); uartcli_println_str("VLOCLK overflow IRQ messages enabled"); } if (!strcmp(buf, "off")) { VLO_TimerA_overflow_mark(0); uartcli_println_str("VLOCLK overflow IRQ messages disabled"); } } else { // Display VLO overflow mark status if (VLO_TimerA_overflow_mark_enabled()) { uartcli_println_str("VLOCLK overflow IRQ messages: enabled"); } else { uartcli_println_str("VLOCLK overflow IRQ messages: disabled"); } } break; case 3: // VLORATE (set divider) if (vlostat & VLO_ENABLED) { if (uartcli_token_arg(1, buf, 32) != NULL) { i = atoi(buf); if (i != 1 && i != 2 && i != 4 && i != 8) { uartcli_print_str("vlorate: Inappropriate divider value: "); uartcli_println_str(buf); uartcli_println_str("Divider must be 1, 2, 4 or 8."); } else { // Set it! VLO_TimerA_set_divider(i); uartcli_print_str("VLOCLK timer divider set to: "); uartcli_println_int(i); } } else { // Display current VLO TimerA divider uartcli_print_str("VLOCLK timer divider set to: "); uartcli_println_int(VLO_TimerA_get_divider()); } } else { uartcli_println_str("VLOCLK timer disabled; ignoring command"); } break; case 4: // HELP uartcli_println_str("HELP -- Command reference"); uartcli_println_str("led : Query red LED status or switch LED on/off"); uartcli_println_str("vlo : Query runtime status of VLOCLK-enabled TimerA or switch on/off"); uartcli_println_str("vloirq : Display whether 16-bit timer overflow IRQ marks are enabled or switch on/off"); uartcli_println_str("vlorate : Display or set the TimerA clock divider"); break; default: uartcli_print_str("Unknown command: "); uartcli_token_cmdstr(buf, 32); uartcli_println_str(buf); } }
  13. Like
    dacoffey reacted to Jack Caster in A simple shell, step by step [eZ430 - RF5000]   
    Hi guys,
    I have started to work on my little project, a simple shell to control the MSP430; as I am a beginner I would like to share my little progresses and at the same time seek for an help to solve the problems on my path.

    #include "io430.h" #include #include //__________MACRO__________ //RED led on P1.0 #define LED_RED BIT0 #define LED_RED_ON (P1OUT |= BIT0) #define LED_RED_OFF (P1OUT &=!BIT0) #define LED_RED_TOGGLE (P1OUT ^= BIT0) //GREEN led su P1.1 #define LED_GREEN BIT1 #define LED_GREEN_ON (P1OUT |= BIT1) #define LED_GREEN_OFF (P1OUT &= !BIT1) #define LED_GREEN_TOGGLE (P1OUT ^= BIT1) //__________HEADER of FUNCTIONS__________ void init_UART(void); void writeChar(char ch); void writeString(char * str); //__________GLOBAL VARIABLES__________ char buffer[200] = {0}; char * welcome = "Welcome"; char * prompt = "msp430>> "; int main( void ) { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; LED_RED_OFF; LED_GREEN_OFF; P1DIR = LED_RED + LED_GREEN; init_UART(); writeString(welcome); writeString(prompt); __low_power_mode_0(); // Interrupts enabled } void init_UART(void) { // Basic Clock System Control 1 BCSCTL1 = CALBC1_1MHZ; // BCSCTL1 Calibration Data for 1MHz // DCO Clock Frequency Control DCOCTL = CALDCO_1MHZ; // DCOCTL Calibration Data for 1MHz // UART Mode P3SEL = BIT4 + BIT5; // USCI_A0 TXD/RXD on P3.4 & P3.5 // USCI A0 Control Register 1 UCA0CTL1 |= UCSSEL_2; // USCI 0 Clock Source 2: SMCLK // USCI A0 Baud Rate 0 & 1 UCA0BR0 = 104; // 1MHz 9600 UCA0BR1 = 0; // 1MHz 9600 // USCI A0 Modulation Control UCA0MCTL = UCBRS0; // USCI Second Stage Modulation Select 0 UCA0CTL1 &= ~UCSWRST; // USCI Software Reset: Initialize state machine // Interrupt Enable 2 IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt } #pragma vector=USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { char character; LED_RED_TOGGLE; character = UCA0RXBUF; // Echo back character if (character != 0x0D) { writeChar(character); // CR = 0x0D } else { writeChar('\n'); writeChar('\r'); //CReturn writeString(prompt); } } void writeChar(char ch) { while (!(IFG2 & UCA0TXIFG)); // USART1 TX buffer ready? UCA0TXBUF = ch; } void writeString(char * str) { int i; for (i = 0; i < strlen(str); i++) { writeChar(str[i]); } }
    My first problem is to find a way to make my welcome message to stay put up to when a new character is received.
    Up to now that is what is happening: these two lines...

    writeString(welcome); writeString(prompt);
    ...seem not to work, but instead in the very moment in which I type a character the functions work.

    My second question is how can I write a function which prints a blinking cursor. It seems not easy!
    Thank you!
  14. Like
    dacoffey got a reaction from bluehash in COMIO Serial IO Shell   
    COMIO is a protocol and application I am developing that allows IO control over a serial line.

  15. Like
    dacoffey reacted to artifus in Fritzing for LaunchPad   
  16. Like
    dacoffey got a reaction from wilywyrm in COMIO Serial IO Shell   
    COMIO is a protocol and application I am developing that allows IO control over a serial line.

  17. Like
    dacoffey reacted to RobG in MIDI Light controller   
    Boards are finally here, passed the smoke test. Will do some serial mode tests before mounting the control board.
    Now I need to find a nice box for it, probably some junction box.

    Optional 595 mounted on the bottom, used for serial mode.

    And here it is with the control board

  18. Like
    dacoffey reacted to larsie in Thermistor code for MSP430   

  19. Like
    dacoffey reacted to cubeberg in Need some SEO help   
    Ok - I think I found something else that's a problem. The forum is generating "noindex" meta tags on forum pages. Must be something in the software - maybe a plugin or option?

  20. Like
    dacoffey reacted to larsie in Simple robot, programmable using buttons   
    Here is a laser cut robot I
  21. Like
    dacoffey reacted to oPossum in MSP430G2553 PWM Outputs   
    3 on 20 pin package or 4 on 28 pin package (SMD only)
    There are 8 analog inputs on P1.0 to P1.7 and only one PWM output conflicts with that range, so you could have 7 analog in, but will also loose hardware UART/SPI/IIC because those share pins with the ADC.
    Timer A0 CCR0: P1.1 or P1.5
    Timer A0 CCR1: P1.2 or P1.6
    Timer A0 CCR2: P3.0
    Timer A1 CCR0: P2.0, P2.3, P3.1 or P3.4
    Timer A1 CCR1: P2.1, P2.2, P3.2 or P3.5
    Timer A1 CCR2: P2.4, P2.5, P3.3 or P3.6
    CCR0 can not be used for PWM. Port 3 in only on 28 pin package.
    For some applications, you may be able to use software PWM. That works on any pin.
  22. Like
    dacoffey reacted to wilywyrm in MSPDice for the 21st century geek   
    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.)

  23. Like
    dacoffey reacted to CorB in MSP430 meets LaCrosse Temperature/Humidity sensor TX3TH   
    Excuses for the long post !!
    After I found out that I could detect signals in the 433Mhz band using an AIR Boosterpack (See viewtopic.php?f=9&t=2944 AIR Boosterpack RF spectrum display) I wanted to display the data I was receiving on the 433 Mhz band.
    Ive got a Lacrosse temperature/humidity logger WS8610 that can read up to 3 external sensors and log the data. These sensors broadcast their data every minute or so.
    Since I have a logger and I have a display you might ask why do you want to read the data ? My motivation for this is simple, the datalogger can only capture data for about 1.5 weeks and then the oldest readings are overwritten and I need to connect the datalogger to an old PC (that still has a USB-DB9 connector) to be able to store the data. If I can read the data directly from the sensors I can hook them up in a system I allready have running with several other sensors (gas, electricityusage, inside temperature) and store the data on the internet. For those that are interested I am using Thingspeak to store my data.
    So last week I started to look at a way to decode the signals I saw coming in using my spectrum display. Luckily other people had allready done a lot of work on the protocol used by the sensors. The sensordata is send using On/Off keying (OOK).
    See http://ftp.f6fbb.org/domo/sensors/tx_signals.php and http:/ftp.f6fbb.org/domo/sensors/tx3_th.php
    After a few days of trial-and-error approach (thanks go to larsie for the feedback and ideas !) I actually was getting signals that could be the sensordata. To cut a long story short, using asynchronous CarrierSense detection on the AIR BOOSTERPACK and timing the length of the pulse coming in I can read the incoming data from several sensors. The software is definitely in its alpha stages. I can read one sensor properly but reading multiple sensors does give problems, if I set the RF registers to read the nearby sensor (3-4 meters away) the far away sensor (>10m) doesnt get picked up. When I set to register to read the far away, the nearby gets picked up but the data isnt as it should be anymore.
    Here's an image to show that I get results that are the same as my LaCrosse display shows (from left to right : MSP430 sandwich, Lacrosse display and a not active TX3TX sensor).

    The code below is based on the same GLCD and TI libraries as I used for my spectrum display project.

    /* * This file is licensed under BSD. The simplicity code is originally copyright Texas Instruments, * but has been adapted by Lars Kristian Roland/Cor Berrevoets * the glcd code is by Lars Kristian Roland/Cor Berrevoets * the tx3th sensor information can be found at http://ftp.f6fbb.org/domo/sensors/tx3_th.php * the sensor first sends temperature information consisting of 11 blocks of 4 bits repeated once * the sensor secondly sends humidity information consisting of 11 blocks of 4 bits repeated once * block 0 is 0000 * block 1 is 1010 (preamble) * block 2 is sensortype 0=temperature E=humidity * block 3 is 4 bits sensorID * block 4 is 3 bits sensorID and another bit (unknown purpose) * block 5/6/7 is temperature in tenths degrees BCD +50 degrees * block 5/6/7 is humidity in tenths percent BCD (always ending at 0) * block 8 = block 6 * block9 = block 7 * block10 = CRC * */ //******************************************************************* // // G2553 // // ----------------- // | | // |VCC GND | // S1/GDO2 |P1.0 P2.6|-RF-GDO0 // S2 |P1.1 P2.7|-RF-CS // SW1 |P1.2 | // LED |P1.3 | // glcd-cs |P1.4 P1.7|<-------| glcd/RF-MISO //glcd/RF-CLK |P1.5 P1.6|------->| glcd/RF-SOMI // S3 |P2.0 P2.5| // S4 |P2.1 P2.4| // |P2.2 P2.3| // | | // ----------------- //******************************************************************* #include "ti/include.h" #include "../library/glcd_charset.c" #include "../library/glcd.c" unsigned long clockcnt=0,lastclock=0; unsigned long lastpulsecnt, pulsecnt=0,faultcount=0, pulselength=0; unsigned char bit; // bitcounter 0..3 unsigned char bitdata[4]={8,4,2,1}; // to create a nibble readout with MSB first coming in char pulseindx; // nibblecounter unsigned char pulsetrain[50],oldpulse[50]; // datapackage storage unsigned char line=4; // display of temperature datapackage int rssi; #define signal BIT2 void setup433MhzOOKreader() { TI_CC_SPIStrobe(TI_CCxxx0_SIDLE); // set IDLE TI_CC_SPIWriteReg(TI_CCxxx0_FREQ2, 0x10); // Freq control word, high byte TI_CC_SPIWriteReg(TI_CCxxx0_FREQ1, 0x00); //Freq control word, mid byte. TI_CC_SPIWriteReg(TI_CCxxx0_FREQ0, 0x00); //Freq control word, low byte. TI_CC_SPIWriteReg(TI_CCxxx0_MDMCFG4, 0x06); // RX bandwidth and datarate MSB TI_CC_SPIWriteReg(TI_CCxxx0_MDMCFG3, 0x37); // datarate LSB TI_CC_SPIWriteReg(TI_CCxxx0_MDMCFG2, 0x00); // no preamble/sync TI_CC_SPIWriteReg(TI_CCxxx0_MDMCFG1, 0x00); // CHANNEL SPACING and channelspacing MSB TI_CC_SPIWriteReg(TI_CCxxx0_MDMCFG0, 0xe5); // x2E5=200Khz x1E5=100Khz x0E5=50Khz x000=25Khz, CHANNEL SPACING LSB TI_CC_SPIWriteReg(TI_CCxxx0_FOCCFG, 0x00); // no IF compensation for OOK TI_CC_SPIWriteReg(TI_CCxxx0_AGCCTRL2,0xc3); // receiver gain 0xAB A B TI_CC_SPIWriteReg(TI_CCxxx0_PKTCTRL0, 0x32); //asynchronous mode TI_CC_SPIWriteReg(TI_CCxxx0_IOCFG0, 0x0E); //GDO0Output Pin Configuration asynchronous output TI_CC_SPIWriteReg(TI_CCxxx0_CHANNR, 48); // change radio to channel 48 in 432Mhz band (50khz spacing) TI_CC_SPIStrobe(TI_CCxxx0_SRX); // goto receivermode } void main (void) { WDTCTL = WDT_MDLY_0_064; // WDT ~0.064ms interval timer IE1 |= WDTIE; // Enable WDT interrupt P1DIR |=signal; TI_CC_GDO0_PxIES &= ~TI_CC_GDO0_PIN; // Int on falling edge (end of pkt) TI_CC_GDO0_PxIFG &= ~TI_CC_GDO0_PIN; // Clear flag for GDO0 TI_CC_GDO0_PxIE |= TI_CC_GDO0_PIN; // Enable interrupt on end of packet RF_init(); // SETUP ANAREN AIR RF __delay_cycles(50000); SPISetup(); // Initialize SPI Display __delay_cycles(100000); clear(); __delay_cycles(100000); //reset the pulsetrain indices and storage arrays for (pulseindx=0; pulseindx<49; pulseindx++) { pulsetrain[pulseindx]=0; oldpulse[pulseindx]=0; } pulsecnt=0; pulseindx=0; bit=0; lastpulsecnt=0; writeInt(0,2,faultcount,3); // display faults writeInt(48,2,pulsecnt,3); // display how many packages have been read setup433MhzOOKreader(); __enable_interrupt(); // enable all interrupts while (1) // do for ever { if (pulsecnt>lastpulsecnt) // display data only of we have received a package { setcharmode(1); // switch to large characters if ((oldpulse[1]==0x0a) && (oldpulse[12]==0x0a)) { unsigned int temperature; unsigned int humidity; temperature=(oldpulse[5]-5)*100+oldpulse[6]*10+oldpulse[7]; writeInt(0,0,temperature,3); humidity=oldpulse[27]*10+oldpulse[28]; writeInt(48,0,humidity,3); lastpulsecnt=pulsecnt; } writeInt(0,2,faultcount,3); // display faults writeInt(48,2,pulsecnt,3); // display how many packages have been read setcharmode(0); // switch to small characters unsigned char temp; char i,x; x=0; // show the 11 nibbles of the temperature part of the package for (i=0; i<11; i++) { temp = oldpulse[i]; temp += (temp > 9) ? 'A' - 10 : '0'; writeChar(x,line,temp); x=x+6; } writeInt(x+6,line,rssi,4); } } } #pragma vector = WDT_VECTOR // - Watchdog timer interrupt vector __interrupt void wdt_isr(void) // This interrupt will occur once per second { // clockcnt++; } #pragma vector=PORT2_VECTOR __interrupt void Port_2(void) { // REALLY cheap debounce. // We can get away with this because we're edge triggering but reading the level. if(TI_CC_GDO0_PxIFG & TI_CC_GDO0_PIN) { pulselength=clockcnt-lastclock; lastclock=clockcnt; if (pulselength<30) {pulsetrain[pulseindx]|=bitdata[bit];} bit++; if (bit==4) {bit=0; pulseindx++;} if (pulseindx>43) // we got all 44 bits in { rssi=TI_CC_SPIReadStatus(TI_CCxxx0_RSSI); __delay_cycles(100); if(rssi < 128) // convert RSSI readout to dB { rssi = -((rssi/2) - 74); } else{ rssi = -(((rssi - 256)/2) - 74); } char j; for (j=0; j<45; j++) {oldpulse[j]=pulsetrain[j]; pulsetrain[j]=0; } //reset indices pulseindx=0; bit=0; //increment the line to display the datapackage line++; if (line>7) {line=4;} if (oldpulse[1]==0x0a) {pulsecnt++;} else {faultcount++; pulsecnt++;} // add a long delay after reading the 44th nibble, corrects possible mistakes also __delay_cycles(10000000); } TI_CC_GDO0_PxIFG &= ~TI_CC_GDO0_PIN; // After pkt RX, this flag is set. } }
  24. Like
    dacoffey reacted to CorB in AIR Boosterpack RF spectrum display   
    Hi all,
    One of the things I wanted to build using the Anaren AIR boosterpack was a mini spectrum "analyzer" or spectrum display. During my holiday i found time to play around with both the AIR boosterpack and the LCD module Lars has produced.
    Although the AIR boosterpack was designed for 868/915 Mhz it seems the receiver inside (CC110L) is sensitive also in the 433Mhz region. The code I share with this mail allows the user (by changing a define) to switch between 3 frequencybands. Two buttons of the LCD package allow change of RX bandwidth and channelwidth.
    THe screenshot below shows a typical readout in the 433 Mhz band in a room where a Lacross TX3TH temperature/humidity sensor is sending data every minute using an OOK protocol (Request: if anybody knows how to receive/decode OOK using a CC110L please inform me). The display shows the low and high frequency in Mhz and shows the frequency with the highest readout (RSSI in dB) in kHz and as a blinking line in the graph.

    If you want to know more about this mini spectrum display or have other comments, feel free to share them.
  25. Like
    dacoffey reacted to simpleavr in webbotlib speech synthesizer on launchpad   
    not sure this is considered a project. the package i am providing allows one to play w/ TTS on a launchpad w/ g2553 chip.
    i did not create the TTS s/w, credit belongs to webbot at http://webbot.org.uk
    instead of publishing derived code, i am publishing a perl script to convert his code for msp430 use.
    this allows me to avoid licensing issues and i think anyone want to implement this should look at the original source.
    the speech system is not high quality but fun to use in projects. i.e. talking clocks, alert / alarm modules, robot voices, etc.
    . s/w only speech synthesizer technique from webbot
    . one pin pwm.
    . text-to-speech and synthesizer code under 10k.
    . fits in a g2553 mcu.
    . hosted in github, search for "webbot_talk430" project
    . there are 4 files.
    . zconv.pl converts the webbotlib speech source codes to a msp430 compatible source.
    . talk.c TTS exercising firmware, talks to PC at 9600bps turns what u type into speech.
    . uart.h uart code
    . common.h some macros i used.
    . pwm hardware hook-up is in talk.c, just one resistor and one capacitor, can be improved by using better filters.

    instructions (as in README and help from conversion script)
    this is a perl script to convert the webbotlib speech sythesizer code from avr
    to msp430 usage. this script is use at your own risk giftware. webbotlib has
    it's own license terms.
    . locate "webbotlib" and download version 1.x, i tried w/ webbotavrclib-1.35
    . inside the package locate and extract the Audio/Text2Speech directory
    . u will see the following files
    . place these files in a same directory as this (zconv.pl) script
    . run it again and this script will
    . extract what's needed, ignore others
    . combine into a tighter package name "../webbot_speech.h"
    . replace avr controls w/ msp430 controls
    . to use it in your firmware, do
    . include "webbot_speech.h"
    . say("Hello World");
    . enjoy and thanks webbot
    <<< IMPORTANT >>>
    please observe the fact that webbotlib is GPL licensed and use / share accordingly
    will be glad to answer questions anyone may have in this thread. happy hacking.
  • Create New...