grahamf72
-
Content Count
189 -
Joined
-
Last visited
-
Days Won
15
Reputation Activity
-
grahamf72 got a reaction from vominhcuog in [Energia Library] MSP430 Real Time Clock
Attached is my latest version of the Real Time Clock library, adapted from xv4y's original library. Some significant changes in this version are:
Now works with both the MSP430G2553 and the MSP430G2452 processors (with some limitations on the 2452). The library may work on other processors, but I don't have any to test with. Rewrite of the logic used to detect the number of days in a month and leap year detection so that it uses considerably less RAM. Option to use the built-in VLO clock. The VLO is much less accurate than the crystal - about the best that can be achieved is accuracy to within a few minutes per day. The advantage of the VLO is that it frees up 2 IO pins, and can be used if you can't solder the tiny crystal to the launchpad. If you don't need a very accurate clock, or have a means of external synchronisation, the VLO may be sufficient for your needs. The #define's that configure the settings of the timer have been moved to a separate RTCconfig.h file, so they are easier to edit without having to edit the main header file. Documentation has been moved from the header file into a separate .txt file. Some example files have been included in the library. Known Limitations:
Because the MSP430G2452 only has one timer, the RTC library cannot be used in conjunction with other functions that also require the timer. This includes Serial, AnalogWrite, Tone, and possibly some others. Because the MSP430G2452 doesn't have hardware serial, this means that the RTC library and Serial are completely incompatible.
RTCplus.zip
-
grahamf72 got a reaction from energia in interrupt pins on msp430F5529
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
-
grahamf72 got a reaction from atmega644 in [Energia Library] MSP430 Real Time Clock
Attached is my latest version of the Real Time Clock library, adapted from xv4y's original library. Some significant changes in this version are:
Now works with both the MSP430G2553 and the MSP430G2452 processors (with some limitations on the 2452). The library may work on other processors, but I don't have any to test with. Rewrite of the logic used to detect the number of days in a month and leap year detection so that it uses considerably less RAM. Option to use the built-in VLO clock. The VLO is much less accurate than the crystal - about the best that can be achieved is accuracy to within a few minutes per day. The advantage of the VLO is that it frees up 2 IO pins, and can be used if you can't solder the tiny crystal to the launchpad. If you don't need a very accurate clock, or have a means of external synchronisation, the VLO may be sufficient for your needs. The #define's that configure the settings of the timer have been moved to a separate RTCconfig.h file, so they are easier to edit without having to edit the main header file. Documentation has been moved from the header file into a separate .txt file. Some example files have been included in the library. Known Limitations:
Because the MSP430G2452 only has one timer, the RTC library cannot be used in conjunction with other functions that also require the timer. This includes Serial, AnalogWrite, Tone, and possibly some others. Because the MSP430G2452 doesn't have hardware serial, this means that the RTC library and Serial are completely incompatible.
RTCplus.zip
-
grahamf72 got a reaction from PNY90 in [Energia Library] MSP430 Real Time Clock
Attached is my latest version of the Real Time Clock library, adapted from xv4y's original library. Some significant changes in this version are:
Now works with both the MSP430G2553 and the MSP430G2452 processors (with some limitations on the 2452). The library may work on other processors, but I don't have any to test with. Rewrite of the logic used to detect the number of days in a month and leap year detection so that it uses considerably less RAM. Option to use the built-in VLO clock. The VLO is much less accurate than the crystal - about the best that can be achieved is accuracy to within a few minutes per day. The advantage of the VLO is that it frees up 2 IO pins, and can be used if you can't solder the tiny crystal to the launchpad. If you don't need a very accurate clock, or have a means of external synchronisation, the VLO may be sufficient for your needs. The #define's that configure the settings of the timer have been moved to a separate RTCconfig.h file, so they are easier to edit without having to edit the main header file. Documentation has been moved from the header file into a separate .txt file. Some example files have been included in the library. Known Limitations:
Because the MSP430G2452 only has one timer, the RTC library cannot be used in conjunction with other functions that also require the timer. This includes Serial, AnalogWrite, Tone, and possibly some others. Because the MSP430G2452 doesn't have hardware serial, this means that the RTC library and Serial are completely incompatible.
RTCplus.zip
-
grahamf72 got a reaction from altineller in [Energia Library] MSP430 Real Time Clock
Updated version of the library attached. Main changes are:
Configuration option allows the Watch-Dog Timer to be used for the RTC instead of TimerA. This also requires replacements for the functions in wiring.c. A side effect caused by limitations of the 430 hardware is that delay, millis and micros only have a resolution of 1.9mS. Added helper functions to convert the hmsDMY time into UnixTime format, return day-of-week, etc. Added an alarm class. Improved documentation. RTCplus.zip
-
grahamf72 got a reaction from Kipz in [Energia Library] MSP430 Real Time Clock
Updated version of the library attached. Main changes are:
Configuration option allows the Watch-Dog Timer to be used for the RTC instead of TimerA. This also requires replacements for the functions in wiring.c. A side effect caused by limitations of the 430 hardware is that delay, millis and micros only have a resolution of 1.9mS. Added helper functions to convert the hmsDMY time into UnixTime format, return day-of-week, etc. Added an alarm class. Improved documentation. RTCplus.zip
-
grahamf72 got a reaction from B@tto in MT3339 + MSP430G2553 issue
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.
-
grahamf72 got a reaction from bluehash in MT3339 + MSP430G2553 issue
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.
-
grahamf72 got a reaction from Fmilburn in Sleep mode during a fixed duration ?
The standard Energia delay() function spends most of its time in LPM0. If you want lower than that you need to set up a timer running off either the optional Crystal or the VLO clock.
As an example for long low power delays, you could do something like the following:
#include <Energia.h> volatile unsigned long delaycounter; void StartTimer() { //To use the VLO, Use the following: BCSCTL1 &= ~DIVA_3; // ACLK without divider - nominally 12kHz BCSCTL3 = (LFXT1S_2); // Source ACLK from VLO TA1CCTL0 = CCIE; // CCR0 interupt activated TA1CCR0=11999; // 12000 ticks is nominally 1 second TA1CTL = TASSEL_1 | ID_0 | MC_1; // Clock for TIMER = ACLK, No division, up mode //Alternatively to use the Crystal for more accuracy use the Following /* P2SEL |= (BIT6 | BIT7); // Reset P2_6 & P2_7 BCSCTL1 &= ~DIVA_3; // ACLK without divider - 32768kHz BCSCTL3 = (LFXT1S_0 | XCAP_3);// Source ACLK from XTal TA1CCTL0 = CCIE; // CCR0 interupt activated TA1CCR0=4096-1; // we are dividing clock by 8, so 4096 ticks = 1 second TA1CTL = TASSEL_1 | ID_3 | MC_1; // Clock for TIMER = ACLK, By 8 division, up mode */ } void StopTimer() { TA1CTL|=TACLR; } //Set Up the Interrupt routine... __attribute__((interrupt(TIMER1_A0_VECTOR))) void timer_isr (void) { ++delaycounter; //increment our seconds counter __bic_status_register_on_exit(LPM3_bits); //exit at full power. } //And here is our delay function... //this will create delays of up to approx 136 years //with 1 second resolution. void longdelay(unsigned long delayseconds) { delaycounter=0; StartTimer(); //start our timer up while (delaycounter<delayseconds) //while we haven't reached our count... __bis_status_register(LPM3_bits+GIE); //switch back to LPM3. StopTimer(); //times up, stop our timers. }; void setup() { Serial.begin(9600); }; void loop() { Serial.println("10 seconds mostly in LPM0 with traditional delay..."); delay(10000); Serial.println("10 seconds in LPM3 with longdelay..."); longdelay(10); };
When I tested this, I was getting about 1300uA (1.3mA) during the traditional delay(). This dropped to about 25uA when it was in the longdelay function.
-
grahamf72 got a reaction from dubnet in will this work / burn out output pin?
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
-
grahamf72 got a reaction from tripwire in Vetinari's Clock
Also, because we are talking about an inductive load, it is also essential to have each pin protected by reverse biased diodes from the pin to each power rail to absorb any transient spikes. When switching coils, it's not hard to get transients in the +/- tens or even hundreds of volts which could easily be fatal to our little 430 mcu's. Common bipolar transistors as used in the original circuit will generally handle these transients no problem.
Sent from my iPad using Tapatalk
-
grahamf72 got a reaction from stasundr in msp430g2553 goes crazy
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.
-
grahamf72 got a reaction from sumotoy in Bug in SPI Library?
I finally managed to track down the register documentation for the Stellaris processor (for some reason i couldn't find it on Ti's site), and it all makes sense now.
The SPI clock frequency is set by 2 registers - CPSDVSR (Clock Prescaler) & SCR (Serial Clock Rate) by the formula SSI Clock = System Clock / (CPSDVSR * (1 + SCR))
Energia's setClockDivider just sets the Clock Prescaler register. According to the spec's of this register it must be an even number between 2 & 254. The LSB is ignored. Consequently by calling the routine with a divisor of 1, it was actually storing 0 and hence seems to go to some error state - the doc's don't say what happens when this is set to 0.
Another limitation is that it won't allow any frequency above 25Mhz for the SPI. Unfortunately it is not possible to achieve the 25MHz maximum SPI speed with a system clock of 80MHz. The following are some of the valid combinations of registers and resulting frequency
CPSDVSR SCR FREQ CPSDVSR SCR FREQ
2 1 20MHz 4 0 20MHz
2 2 13MHz 4 1 10MHz
2 3 10MHz 4 3 5MHz
2 4 8MHz 4 4 4MHz
2 7 5MHz 4 9 2MHz
2 9 4MHz 4 19 1MHz
2 15 2.5MHz
2 19 2MHz
The function ROM_SSIConfigSetExpClock sets the registers in such a way that you get the frequency closest to the frequency set in that function. Because setting it 16MHz (as suggested in your comment on the github page) is actually impossible, it actually sets the speed to 20MHz. I'd suggest an improvement would be in the config to set the CPSDVSR to 2, and the SCR to 9 to get the default 4Mhz clock. Then in setClockDivider change the SCR rather than the CPSDVSR.
-
grahamf72 got a reaction from ILAMtitan in Vetinari's Clock
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 } -
grahamf72 got a reaction from mgonsalv in Excessive current useage when analogReference is not DEFAULT
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
-
grahamf72 got a reaction from altineller in analogWrite bug with msp430g2553 in energia
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.
-
grahamf72 got a reaction from GeekDoc in Vetinari's Clock
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 } -
grahamf72 got a reaction from dubnet in Vetinari's Clock
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 } -
grahamf72 got a reaction from abecedarian in Oversampling, averaging and getting confused.
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
-
grahamf72 got a reaction from manhdan in [Energia Library] MSP430 Real Time Clock
Updated version of the library attached. Main changes are:
Configuration option allows the Watch-Dog Timer to be used for the RTC instead of TimerA. This also requires replacements for the functions in wiring.c. A side effect caused by limitations of the 430 hardware is that delay, millis and micros only have a resolution of 1.9mS. Added helper functions to convert the hmsDMY time into UnixTime format, return day-of-week, etc. Added an alarm class. Improved documentation. RTCplus.zip
-
grahamf72 got a reaction from manhdan in [Energia Library] MSP430 Real Time Clock
Attached is my latest version of the Real Time Clock library, adapted from xv4y's original library. Some significant changes in this version are:
Now works with both the MSP430G2553 and the MSP430G2452 processors (with some limitations on the 2452). The library may work on other processors, but I don't have any to test with. Rewrite of the logic used to detect the number of days in a month and leap year detection so that it uses considerably less RAM. Option to use the built-in VLO clock. The VLO is much less accurate than the crystal - about the best that can be achieved is accuracy to within a few minutes per day. The advantage of the VLO is that it frees up 2 IO pins, and can be used if you can't solder the tiny crystal to the launchpad. If you don't need a very accurate clock, or have a means of external synchronisation, the VLO may be sufficient for your needs. The #define's that configure the settings of the timer have been moved to a separate RTCconfig.h file, so they are easier to edit without having to edit the main header file. Documentation has been moved from the header file into a separate .txt file. Some example files have been included in the library. Known Limitations:
Because the MSP430G2452 only has one timer, the RTC library cannot be used in conjunction with other functions that also require the timer. This includes Serial, AnalogWrite, Tone, and possibly some others. Because the MSP430G2452 doesn't have hardware serial, this means that the RTC library and Serial are completely incompatible.
RTCplus.zip
-
grahamf72 got a reaction from MrChunckuee in Problem with msp430, LCD16x2 and ADC
Are you using the 2231? I suspect the code is too big for the little processor.
-
grahamf72 got a reaction from pliyt in [Energia Library] MSP430 Real Time Clock
Updated version of the library attached. Main changes are:
Configuration option allows the Watch-Dog Timer to be used for the RTC instead of TimerA. This also requires replacements for the functions in wiring.c. A side effect caused by limitations of the 430 hardware is that delay, millis and micros only have a resolution of 1.9mS. Added helper functions to convert the hmsDMY time into UnixTime format, return day-of-week, etc. Added an alarm class. Improved documentation. RTCplus.zip
-
grahamf72 got a reaction from yosh in [Energia Library] Fixed point math
This isn't my work, it is 99.9% from the libfixmath library found at http://code.google.com/p/libfixmath/ I have just made very minor alterations by putting some necessary #define's into fix16.h to allow it to compile on Energia (the standard library requires -D compiler options), and added a pow() function.
While working on an altimeter project, I needed to convert barometer pressure to altitude which required quite a bit of floating point math. On small microcontrollers, floating point is typically bad to use - it is expensive in both code size, and execution time. In my case, I was having difficulty getting my code to fit into the 16k on the 2553. For simple mathematic functions, you can often avoid floating point and get by with integers. But with the need to raise numbers to the power of 1/5.257, pure integer math was out of the question for my needs. I was having difficulty getting my code to fit into the 16k on the 2553. Even a very simple sketch that just did a calculation of the barometric formula (without any code to read from the barometer IC or output the display in readable form) ran to over 6k.
Enter this library which uses a fixed 16.16 format number held as a 32bit signed long, as a compromise between floating point & integer math. Internally, this allows it to use pure integer math resulting in higher speed and smaller code size. Using this library, my basic sketch to calculate the barometric formula dropped from over 6k in size to about 2.5k.
Compared to floating point there are still some limitations - the maximum number is +/-32,767.9999... so there may be some instances where you need to divide your numbers to ensure you don't overflow. Also the precision isn't as good as a float, but for most needs it should work fine as a good lean alternative to pure floating point. In my case, the altitude error compared to pure floating point was in the order of 0.001m - the barometer is not nearly that accurate so errors introduced by the maths were insignificant.
Documentation is available at the original source website, along with examples, although the examples are not 430 compatible. The attached library will compile as-is for the 430 platform. I haven't tested it on Stellaris, but there is no reason it shouldn't also work. On Stellaris you may want to experiment with the #defines in the fix16.h file. Because the Stellaris is 32bit you can definitely take out FIXMATH_OPTIMISE_8BIT which will increase performance.
libfixmath.zip
-
grahamf72 got a reaction from spirilis in Bug in SPI Library?
I finally managed to track down the register documentation for the Stellaris processor (for some reason i couldn't find it on Ti's site), and it all makes sense now.
The SPI clock frequency is set by 2 registers - CPSDVSR (Clock Prescaler) & SCR (Serial Clock Rate) by the formula SSI Clock = System Clock / (CPSDVSR * (1 + SCR))
Energia's setClockDivider just sets the Clock Prescaler register. According to the spec's of this register it must be an even number between 2 & 254. The LSB is ignored. Consequently by calling the routine with a divisor of 1, it was actually storing 0 and hence seems to go to some error state - the doc's don't say what happens when this is set to 0.
Another limitation is that it won't allow any frequency above 25Mhz for the SPI. Unfortunately it is not possible to achieve the 25MHz maximum SPI speed with a system clock of 80MHz. The following are some of the valid combinations of registers and resulting frequency
CPSDVSR SCR FREQ CPSDVSR SCR FREQ
2 1 20MHz 4 0 20MHz
2 2 13MHz 4 1 10MHz
2 3 10MHz 4 3 5MHz
2 4 8MHz 4 4 4MHz
2 7 5MHz 4 9 2MHz
2 9 4MHz 4 19 1MHz
2 15 2.5MHz
2 19 2MHz
The function ROM_SSIConfigSetExpClock sets the registers in such a way that you get the frequency closest to the frequency set in that function. Because setting it 16MHz (as suggested in your comment on the github page) is actually impossible, it actually sets the speed to 20MHz. I'd suggest an improvement would be in the config to set the CPSDVSR to 2, and the SCR to 9 to get the default 4Mhz clock. Then in setClockDivider change the SCR rather than the CPSDVSR.