Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


grahamf72 last won the day on January 17

grahamf72 had the most liked content!

About grahamf72

  • Rank
    Level 2

Profile Information

  • Location

Recent Profile Visitors

786 profile views
  1. When you tested it away from the board, was it still getting it's power from the same supply? I'm wondering if it is a decoupling issue (or something simpler like your power supply is having a voltage drop under the load of both the GPS and the MCU). Do you have the power to both the MCU and the GPS adequately decoupled with capacitors situated as close as possible to the power pins of the IC's? Generally I would use decoupling capacitors of 0.1uF and 10-47uF with the MSP430. The 0.1uF covers the system clock frequency range, while the larger capacitor covers the frequencies used by the low speed oscillator (VLO clock or the crystal), UART etc. Using a GPS, I'd probably also put in a 0.001uF to cover the gigahertz range of frequencies that GPS uses. These are typical values - the actual theory behind optimal decoupling capacitor values is quite complex, but the figures above will do the job fine on most designs.
  2. Why not just do something simple like this Apologies for the rough drawing, it was with my finger on an iPad. When the MSP pin is high, the left transistor turns on, turning on the LEDs in its collector. This pulls the base of the left transistor down to below its turn-on voltage, so no current flows through its base, turning its LEDs off. When the MSP goes low, the left transistor goes off. Because it is no longer sinking the bottom of the 2k2 resistor to ground, current is able to flow through the 2k2 resistor and 47k resistor, through the base of the right transistor, turning it and it's LEDs on. Because the 2k2 & 47k resistors form a voltage divider, the voltage drop across the 2k2 is less than the forward voltage of the left LEDs, so no current flows through them, and they remain off. Sent from my iPad using Tapatalk
  3. I think I've solved it. Mine is working, even when I changed to P1_2. But then I noticed that it was blinking about once every second, not once every 3 seconds as it should. That indicated to me that the clock it was using for the timer was about 3x faster than VLOCLOCK should be. What is 3x faster than VLOCLOCK? The 32768 crystal, and it just so happens my launchpad has the crystal. Grabbed a launchpad without the crystal and I got the failure. Then I realised, nowhere in the above code is the clock source for ACLK configured, so it is probably defaulting to the crystal. I added BCSCTL3=LFXT1S_2; to the setup() just before the lines to configure TimerA, and now it is running with approx 3 seconds between blips as expected on a board without the crystal. Sent from my iPad using Tapatalk
  4. I've had a bit of a play, and the following code (a mash up of yours and roadrunner's) is working fine, going into LPM3 with about 50uA according to my meter. Note that I have edited the header for the DHT22 library to comment out the #define DEBUG, and that my data pin for the DHT22 is on P1.4. // Include application, user and local libraries #include "DHT22_430.h" /// /// @brief Pin for DHT22 signal /// @n Connect /// * pin 1 (on the left) of the sensor to +5V /// * pin 2 of the sensor to DHTPIN /// * pin 4 (on the right) of the sensor to GROUND /// @n Place a 10k resistor between pin 2 (data) to pin 1 (power) of the sensor /// #define DHTPIN P1_4 DHT22 mySensor(DHTPIN); int wakeupCounter; int frequency; #define LED P1_0 void setup() { TACCTL0 = CCIE; TACCR0 = 12000; //1 second TACTL = MC_1 | TASSEL_1; for (int i=0;i<16;i++) //put all pins in INPUT, helps cut power consumption pinMode(i,INPUT); mySensor.begin(); pinMode(LED,OUTPUT); digitalWrite(LED,0); } void loop() { _BIS_SR(LPM3_bits); int flag = mySensor.get(); int h = mySensor.humidityX10(); //t = mySensor.temperatureX10(); if (flag) { if(h>=485) { digitalWrite(LED,HIGH); //on delay(5); //this maybe could be optimized without using delay() but since this is only a few ms, I think it's ok for now digitalWrite(LED,LOW); //off frequency=3; } else frequency=10; } } #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer0_A0 (void) { if(wakeupCounter % frequency == 0) { //check every 10 seconds and sleep deep meanwhile __bic_status_register_on_exit(LPM3_bits); wakeupCounter=0; } wakeupCounter++; }
  5. It looks like you are using rei_veilo's DHT22 library. Did you edit the header file and disable the DEBUG ? The reason I ask, by default his library uses the serial port to output debugging information. Because the 2452 lacks hardware serial, it uses timer_serial, and the 2452 only has 1 timer. If you are trying to use the timer to manage your wake times, it will clash with the timer that timer_serial uses, and hence you'll see funny behaviour like what you are seeing. I haven't actually used your code to see if this is the problem, but it is what jumps out at me from reading the thread. -------------- Edit -------------- Had another look, and I'm almost certain that the serial debug code in the library is the source of your frustrations. You are using P1_2 for your sensor, which is the TX pin for the 2452's timerserial library. I'd say that what's happening is the serial code in the debug is sending data on P1_2, which is messing up the DHT22. The reason you need the 1 second delay in LPM3, is to give the timerserial library time to clear the serial queue.
  6. The only thing that jumps out at me is that your LED is connected to the serial RX pin. I know you aren't using serial RX but I wonder if using it in this fashion is interfering with the serial routines. Other than that, the RTCplus library is more RAM hungry than it should be. When I did it, I was aiming for small code size rather than small RAM usage. The above shouldn't run out of RAM, but if it is only a snippet from a larger piece of code, then it is possible you are encountering RAM problems. As for the suggestion above about crystal capacitors, the MSP430 has built-in crystal caps, which the RTCplus library enables when it enables the 32k crystal. However, the library does activate the 12.5pF capacitors, which are the ones used by the crystal that ships with the Launchpad. Check the specs for your crystal and if it requires different values, you can change it in RTCplus.cpp - change the XCAP value in line 45 - XCAP_1 for 6pF, XCAP_2 for 10pF.
  7. Only Port 1 & Port 2 are interrupt capable. All pins on these ports are interrupt capable, i.e. P1_0->P1_7, P2_0->P2_7
  8. In your main loop, put your call to BIS_SR... inside your while(1) loop, and take the call to BIS_SR out of your interrupt. I think it is ending up in your while loop, and not going back to LPM. Also, it probably wouldn't hurt to explicitly clear REFON bit. I know the family guide says the reference is automatically turned off, but it can't hurt. Sent from my iPad using Tapatalk
  9. I've been using the libfixmath library (I posted an energia port in the Libraries sub forum), which compiles considerably smaller than the gcc floating point library, and yields accurate results. The 2553 has plenty of grunt to calculate altitudes from pressure and log and/or display them. But... If all you are doing is logging altitude during the flight for later viewing, I'd just be logging the raw pressure readings. Then you can do all the funky maths on the computer that you use to view the results.
  10. My preferred method is to create macros to make things more readable. Plus if you change which pin something is connected to, you just need to modify the macros. So for example I might have something like the following: #define RED BIT0 #define RED_ON {P1OUT |= RED;} #define RED_OFF {P1OUT &= ~RED;} #define SWITCH BIT4 #define IS_SWITCH_PRESSED (!(P1IN & SWITCH)) //Switch is active low, so we invert the state. void setup() { pinMode(P1_0, OUTPUT); pinMode(P1_3, INPUT_PULLUP); } void loop() { if (IS_SWITCH_PRESSED) RED_ON; else RED_OFF; } Obviously this little example doesn't warrant the use of direct hardware manipulation, but gives a basic example of how I use the macros. When doing it this way, you do have to be careful to not incorrectly mix pin naming styles. The Energia pin names P1_0, P1_3 etc are NOT synonyms for BIT0, BIT3 etc, so a command like "pinMode(SWITCH, INPUT)" won't give the expected results. Likewise "(P1IN & P1_3)" won't give expected results.
  11. I've improved the code a little, so here is my updated version. Fixes include: 1. Using a bit array instead of a byte array, dramatically reduces the amount of RAM used, so that smaller MSP430's can be used. I have been using an F2012, only because it was the cheapest DIP MSP430 my supplier had on hand. It should compile and work with pretty much any of the low end processors. I've tested with the F2012 & G2452, but it also compiles with the G2231, so I'd expect it should operate fine. 2. Previously while the motor was turned on, it used a simple __delay_cycles loop for the timeout. This is quite heavy on power. I have changed it so it utilises TimerA so that it can go down to LPM3 while it is providing the motor pulse. 3. The original code had a bug in that when the coil was off, both PNP transistors were turned on. PNP transistors turn on when their base is brought low, and since in the idle state the original code set those pins to 0, both transistors were turned fully on. This didn't result in current flowing through the motor, but base current was constantly flowing through the transistors - approx 3mA each. This sapped battery life. With the original code, I was getting about 1 month on a pair of AA alkaline batteries. With my changes I've had a clock running for about 6 months now. /****************************************************************************** * * Project : Vetinari Clock * Target CPU : MSP430G2553 * Compiler : CCS 5.2.1 * Copyright : None * Version : $Revision: 1A * \file main.c * \brief The Vetinari clock is from a book series known as Discworld, where * Lord Verinari has a clock in his waiting room which has an irregular tick. The * idea of the clock is to add a sense of unease and anxiety to anyone in the waiting * room since their brain doesn't filter out the ticks like a normal clock. * * To accomplish this task on a 430, we create an array of possible time frames to * tick the clock, and parse through it at 4Hz. The array is 32 entries long, so it * equates to 32 seconds in the real world. By randomly setting 32 of the elements high, * we create a timing sequence. A high element will generate a tick of the clock. This * means a second on the clock can be as little as 250ms, or as long as 24 seconds, and * still keep accurate time. ***************************************************************************** * * Code modified by Graham Fountain to: * Use a bit array instead of byte array. This is much more RAM efficient and * allows a smaller 128B device to be used instead of needing a 256B device. * Tested with an MSP430F2012 (which at the time was the least expensive MSP430 * in DIP casing my supplier had in stock). * * The delay code that conrols how long the pulse is delivered to the motor * has been changed from a simple __delay_cycles to use TimerA. This allows us * to drop into LPM3 mode while the motor is pulsing, saving considerable power. * In my tests, a pair of AA batteries lasted about 1 month with the __delay_cycles * code, while they lasted more than 6 months with the TimerA code. * *********************************************************************** * * H Bridge Configuration. * The below code is configured for the below configuration of the * H Bridge. If you use different pins to control transistors then * use different values for COIL_OFF, COIL_ONE & COIL_TWO * * V+ ----------------+-----------+ * | | * E E The top two transistors are PNP, eg BC557 * P1.3<---RESISTOR---B B---RESISTOR--->P1.2 * C C * | | * +---MOTOR---+ * | | * C C * P1.1<---RESISTOR---B B---RESISTOR--->P1.0 * E E The bottom two transistors are NPN, eg BC547 * | | * GND ---------------+-----------+ * * * *****************************************************************************/ #include "msp430.h" #include <stdint.h> #include <stdio.h> #include <string.h> /* Defines - Too lazy to put these in a header, maybe later */ /* How many clock cycles cycles to keep the io high * This will chgange depending on the model of clock movement used */ #define ENERGISE_TIME 820 //time in 1/32768 clock cycles. 820 = 25mS /* IO Mapping */ #define COIL_OUT P1OUT #define COIL_DIR P1DIR /* H-Bridge control pins */ /* * NB: PNP Transistors are ON when low, OFF when high * NPN Transistors are OFF when low, ON when high */ #define COIL_OFF (BIT2 | BIT3) //Both PNP's high (off), Both NPN's low (off) #define COIL_ONE (BIT2 | BIT0) //B0101 PNP on P1.3 on, PNP on P1.2 off, NPN on P1.1 off, NPN on P1.0 on #define COIL_TWO (BIT3 | BIT1) //B1010 PNP on P1.3 off, PNP on P1.2 on, NPN on P1.1 on, NPN on P1.0 off /* Lazy man globals*/ static uint16_t timingSequence[8]; //8 x 16 bits = 128 bits inline uint16_t GetBit(uint16_t x) //get the current value of bit x { return (timingSequence[x>>4] >> (x & 0xF)) & 0x1; //x>>4 is our index to the array (top 3 bits). x & 0xF is the bit we want. } inline void ClearAllBits() //0 the array. This loop takes less code than memset { for(int i=0;i<8;i++) timingSequence[i]=0; } inline void SetBit(uint16_t x) //set bit x of the array { timingSequence[x>>4] |= (1<< (x & 0xF)); } inline void delay() //delay for the period specified by ENERGISE_TIME. { TA0CCR0= ENERGISE_TIME; //set what we will count to. TA0CCTL0 = CCIE; //enable CCR0 interrupt TA0CTL = TASSEL_1 | MC_1 | TACLR; //ACLK (the crystal), count up, reset any value currently in the timer LPM3; //wait until the interrupt happens. TA0CCTL0 = 0; //reset the timer TA0CTL =0; } /* * send a pulse to the clock coil */ void pulseClock(void) { /* the polarity on the coil must swap each time it ticks, so we need to keep track of it */ static uint8_t polarity; if (polarity == 0) { COIL_OUT = COIL_ONE; delay(); COIL_OUT = COIL_OFF; polarity = 1; } else { COIL_OUT = COIL_TWO; delay(); COIL_OUT = COIL_OFF; polarity = 0; } } /* * Using a LFSR, generate a "random" 16-bit number. This was snagged from wikipedia */ uint16_t get_rand(uint16_t in) { uint16_t lfsr = in; static unsigned bit; static unsigned period = 0; /* taps: 16 14 13 11; feedback polynomial: x^16 + x^14 + x^13 + x^11 + 1 */ bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1; lfsr = (lfsr >> 1) | (bit << 15); ++period; return(lfsr); } /* * Reset the clock sequence, runs every 32 seconds */ void ResetSequence(void) { uint8_t i=32; uint8_t location; static uint16_t feedback = 0xACE1; /* Zero out all elements */ //memset(&timingSequence, 0x0, sizeof(timingSequence)); ClearAllBits(); /* The array needs to have 32 random elements set high. * To do this we generate 32 different random numbers to use as indexes for the bits that will be set high. * If the index is already set, we just discard that number and try for a new one. */ do{ /* get a new random number */ feedback = get_rand(feedback); /* We only want the lower 7 bits since it's a 128 element array * The 16-bit number is still used so that we get a longer * chain in the LFSR before it repeats */ location = 0x7F & feedback; /* If the random location has already been set high, we ignore the random number */ if(GetBit(location) == 0) { /* Other wise we set the element */ SetBit(location); /* and decrement the counter */ i--; } /* This needs to be done 32 times */ }while(i); } /* * I setup the MSP, and run the main program loop */ int main(void) { /* counter to determine when 32 seconds have past */ uint8_t counter = 0; if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF) { // If calibration constants erased, do not load, trap CPU!! while(1); //G_uc_SystemFailureCode = McuCalValueFail; } // Set DCOCLK to 1MHz DCOCTL = 0x00; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; /* setup watchdog for a .25s interval * WDT ISR set at watchdog_timer(void)*/ WDTCTL = WDT_ADLY_250; IE1 |= WDTIE; /* Enable Osc Fault */ IE1 |= OFIE; /* Setup IO */ COIL_DIR = COIL_ONE | COIL_TWO; COIL_OUT = COIL_OFF; /* Initialize the pulse sequence */ ResetSequence(); /* Enter LPM3 w/interrupt */ _BIS_SR(LPM3_bits + GIE); while(1) { /* If this element of the sequence is high, we need to tick the clock */ if (GetBit(counter)) { pulseClock(); } /* Increment the counter to get us closer to 32 sec */ counter++; /* The WDT runs at 4Hz, so 32sec at equates to 128 ISR firings * At the 32 sec mark, we want to reset the counter and generate a new pulse sequence */ if (counter == 128) { counter = 0; ResetSequence(); } /* Enter LPM3 w/interrupt */ _BIS_SR(LPM3_bits + GIE); /* Once the WDT interrupt fires, it will return here looping back to the start of the while loop */ } } #pragma vector=TIMER0_A0_VECTOR __interrupt void timera0 (void) { _BIC_SR_IRQ(LPM3_bits); //we don't need to do anything but make sure we are woken up. } /* * The watchdog timer is actually useful */ #pragma vector=WDT_VECTOR __interrupt void watchdog_timer (void) { /* Clear LPM3 bits from 0(SR) * This will send us back to the main while loop */ _BIC_SR_IRQ(LPM3_bits); } /* * Just in case */ #pragma vector=NMI_VECTOR __interrupt void nmi_ (void) { uint16_t i; do { IFG1 &= ~OFIFG; // Clear OSCFault flag for (i = 0xFFF; i > 0; i--); // Time for flag to set } while (IFG1 & OFIFG); // OSCFault flag still set? IE1 |= OFIE; // Enable Osc Fault }
  12. I'd typically use the first method when measuring something that changes slowly compared to the sample rate. The second method would be when the thing being measured is likely to rapidly change and the most recent result is the most important. For example if I was sampling barometric pressure, I'd use the first method for a weather station, but the second method for an altimeter. Sent from my iPad using Tapatalk
  13. On the MSP430G2553 P2_1 and P2_2 are analog write capable. But they are both connected to TimerA1 CCR1, so if you use analogWrite on both, they will both deliver the same output. You need to change one of your pins to one that is on a different Timer or a Different CCR register. Options include: P1.2, P1.6 or P2.6 - all on Timer0, CCR1 P2.4 or P2.5 - on Timer1, CCR2 This is a common mistake with analogWrite on the MSP430G2 launchpad - although the device has 7 pins capable of PWM output, the way the timers are connected there are only 3 PWM channels.
  14. I'll also add, that for a common anode LED display using an NPN transistor such as the BC547 is probably not the best option, as the maximum voltage at the emitter is the base voltage less 0.65V. A high from the MSP430 is typically .3V below Vcc, so with the 3.6v supply of the launchpad, you'll only get 2.65V at the anode. The pins driving the cathode will typically go to Vss+0.3V, so you are only left with 2.35v across the LED, which will probably be enough for most red LEDs, but is barely enough for yellow or green, and definitely not enough for blue or white. A better solution is to use a PNP transistor such as the BC557. The emitter is connected to your positive supply, the base (through a resistor) to the MSP430 pin, and the collector to the LED anode. Doing it this way becomes negative logic - i.e., the transistor & LED are turned on when the output pin is set to low. As for code, the basic code would look something like the following... const uint8_t anode_pins[4]={P2_0, P2_1, P2_2, P2_3}; //the pins that our anodes are connected to. //note that the rest of this code assumes that you are //using a PNP transistor to drive the anodes as //recommended above. uint8_t display_segments[4]; //this array holds the values for each of the digit's segments. //display_segments[0] is the first digit, [1] is the 2nd etc. //each bit is active low, so a value of B11111111 would have all //segments off, while B000000000 would have all segments on. //the actual mapping of the bits depends on the mapping of your pins //to the segment displays, but if you have P1_0 -> a (top segment), //P1_1 -> b (right-top segment), P1_2 - > c (right-bottom segment) etc, //then a value of B11111000 would be a 7 (a, b & c lit) // // // put your setup code - you will want to set your pins to outputs, and initially set all // the pins to high // //code snippet to update display. Each time you call this function, it will light up the //next digit of the LCD display. This routine should be called frequently - preferably at //least 100 times per second, so that the display won't have noticeable flicker. //You could call this in your loop() routine if it doesn't do things like have big delays, //or for more advanced usage, set up a timer with an interrupt routine. // void DisplayNextDigit() { static uint8_t current_digit = 0; digitalWrite(anode_pin[current_digit],1); //turn off the last digit that was displayed current_digit++; //step up to the next digit if (current_digit==4) current_digit=0; //if we were on the last digit, go back to the 1st P1OUT=display_segments[current_digit]; //load the cathode values for the segments. //we use direct register access rather than //digitalWrite so we can set all segments //simultaneously for better speed & less code. digitalWrite(anode_pin[i],0); //turn the digit on }
  15. Personally I'd be interested in something that broke out a higher end chip (eg f5xxx, cc430f5xxx, g2955) to a 40 pin dip footprint, probably with no other support circuitry, or maybe just pads for a crystal, but wouldn't be interested in breakouts for chips already available in dip, as I don't really see a point. Sent from my iPhone using Tapatalk
  • Create New...