Jump to content
43oh

basil4j

Members
  • Content Count

    76
  • Joined

  • Last visited

Posts posted by basil4j

  1. Ok ive been thinking about the lookup table. If I make a table and lookup the result of P0/P, to find the result for the 'power of' bit that should work. Let's say I make 2k entries in the table and they are each signed long thats 8k FRAM right? Is 2k samples ridiculous?

     

    Sent from my GT-I9300 using Tapatalk

     

     

  2. Hi,

    I chose sensor as I need (wanted) to measure to 100k ft altitude and have a very small footprint. A bit off subject but here is my PCB to give you am idea of why a needed a tiny package...

     

    Posted Image

     

    Sent from my GT-I9300 using Tapatalk

     

     

  3. Yup, been suggested lol

    My problem now is not how long it takes, but how much RAM the floating point math requires.

    During run time I can get away with comparing pressure with pre-set pressure target. However when the altimeter has detected landing, I want it to 'beep out' the max altitude, so I will need to calculate altitude at least once. This means the math function will still be there and still hogging all my space :(

  4. 0.2m may be unnecessary, but 0.5m would be nice.

    Its actually a bit inaccurate stating my accuracy/resolution as a distance, because the rate of change of pressure vs altitude changes as we go up, so it should really be expressed in mbar which is after all what we are measuring...

     

    The sensor has a resolution of 0.012mBar and an accuracy of +/- 1mbar.

  5. :blush: sorry for not paying attention. Would it be feasible to approximate the curve with a look-up table and some linear or polynomial interpolation?

    Potentially. However would that be smaller than the math library? We are talking 30000m max altitide with a resolution of .2-.5m (I forget which term to use lol). Accuracy is important so I wouldn't want it to be too linear.

     

    I understand the basic concept of lookup tables but I have never really looked into them (haha) so dont know the finer details. Im guessing this is where interpolation comes in? :)

     

    Sent from my GT-I9300 using Tapatalk

     

     

  6. Ok, have managed to get my accelerometer math into fixed point which was pretty easy.

        		//Calculate temperature compensated pressure.
        		/*
        		  	dT      = temp reading - Tref
    				temp  	= 2000 + dT * TEMPSENS / 2... Result is signed short (20.01deg =  2001 etc)
    				OFF   	= POFF * 2^16 + (TCO*dT)/2...Result is signed 64bit(??) long long. 
    				SENS 	= PSENS * 2^15 + (TCS * dT)/2^8.....Again, 64bit result
    				P       = (ADC Reading * SENS / 2^21 - OFF)/2^15
        		*/
    
         		pDT 		= bar[0] - Tref * 0x100;
        		pTEMP 		= 2000 + pDT * TEMPSENS / 0x1000000;
        		pOFF 		= OFF * 0x10000 + (TCO * pDT) / 0x80;
        		pSENS		= SENS * 0x780 + (TCS * pDT) / 0x100;
        		pPres		= (bar[1] * pSENS / 0x200000 - pOFF) / 0x8000; 

    The barometric stuff is proving difficult still.

     

    This POW function is what really puts it over the top, it adds about 600 RAM usage. I dont know much about how the routine works so I have a few questions.

    Will changing the number of decimal places in the exponent reduce RAM requirements?

    Is there any way to do fixed point POW without using this function? The exponent ranges from +0.19026666 to -0.08196102

     

    Under 'failed allocation', I see '.data' is in there twice, and each entry seems to have identical values (450byte each to make a total 900 unallocated). Why is this?

  7. Over in the Energia libraries forum I have posted a port of the libfixmath 16.16 fixed point math library. It is not Energia specific, so should compile if you are using CCS. It is much smaller and faster than the floating point libraries, and is more than accurate enough for barometric altitude calculations. The whole reason I ported it was because I was using a BMP085 on an MSP430G2553 and the floating point was taking up so much flash I didn't have enough left to do anything useful.

    Thanks! Ill take a look!

     

    Does the fact that the math routines have a 'do not optimise' flag mean anything? Thats what the compiler is saying and im not sure the effect its having

     

    Sent from my GT-I9300 using Tapatalk

     

     

  8. Hi Enl,

     

    I am using MSP430_math.h which is, I believe, MSPMATHLIB?

    Making that math all 1 line doesnt change anything unfortunately.

     

    I have to reduce the buffer to 444bytes to fit it in, but that takes it right to 1024bytes RAM...

     

    Using Whole program optimisation for size has a negligible effect.

     

    Im sure most of this could be done in fixed point, and I will only ever need 8 decimal places, but I have no idea where to start with fixed point...

    EDIT : Ill start by reading this http://www.ti.com/lit/an/slaa329/slaa329.pdf

     

    Edit 2: Plenty of good stuff on Wikipedia too!

     

  9. Ok looks like I do have a problem :/ When I add anything that needs the math library (either msp430_math.h or just math.h) my program wont fit in RAM.

     

    I have a 0.4second circular buffer which is 736 bytes, which if I reduce for 368 bytes allows me to fit everything in. Trouble is 0.2 second is hardly enough time as I need to store the 0.4 seconds of data prior to launch detection (which is delayed by a smidgen to prevent false detection).

     

    Also, the math library takes my FRAM usage from 2700bytes to 14438bytes! Nearly full!

     

    This is all just with the addition of

     

         palt = psealevel / pres;
        palt = pow(palt,lr);
        palt = palt - 1;
        palt = palt * (tempsealevel + 273.15f);
        palt = palt * 153.84615;
     
    (Even if I just add the first line I get these problems)
     
    Any tips? I can understand the FRAM, but the math library must a heck of a lot of variables to use that much RAM...
  10. Fred & Enl. I completely agree, I always start a program with the idea in mind that it has to make sense for someone else to read it.

    I asked about optimising because I like to learn all I can about whatever i'm doing to enable me to make smart choices. This was an educational thread, not one which is currently critical to my project. 

     

    As it is, I have already applied some of the suggestions to some non-math code in my interrupts to keep them as fast as possible :) And they were a bit convoluted...

     

    Fred, not that it is too important in the scheme of things, but I need to do all the math within 5ms. Parts of the math need to be performed at 200Hz, and the other bits cant hold it up :) But as ENL said (and has been pointed out to me in other threads), even then its not something I need to worry about, because with a 20Mhz clock I get 100,000 clock cycles to work with...

     

    Regarding size. 736 bytes of my 1kb are being consumed by a circular buffer :/ This doesn't leave me with much

  11. Ok I was thinking about what Enl said about pre-computing stuff.

     

    Pressure target for altitude is easy. I can do this on the pad at any frequency, say 1Hz, and stop after say 30 seconds to allow everything to stabilise and average out.

     

    altitude = user altitude target

    p0 = sea level pressure (changes depending on the weather)

    T = temperature at sea level (changes depending on the weather)

    L = lapse rate (Can be determined based on use configured altitude target and 4 'if else'

    ^ = to the power of, not XOR :)

     

    p = p0 * (1- (L*altitude/T)) ^ (0.2840437/8.31447*L)

     

    In flight I still need to calculate temperature compensated pressure. This needs to be done within 5ms on a 20Mhz clock which I understand shouldn't be a problem.

    The actual ADC readings from the barometer are only occurring at 50Hz, but the math is all being done in the (interruptable) main loop, and so the time frame is determined by the accelerometer math which is being performed at 200Hz and is also in the main loop.

     

    dT      = temp reading - Tref.................... ....(Tref is a value stored in baro, so only needs to be read once. These values are signed shorts)

    temp  = 2000 + dT * TEMPSENS / 2........... (TEMPSENS is another variable stored in baro, read once). Result is signed short (20.01deg =  2001 etc)

    OFF   = POFF * 2^16 + (TCO*dT)/2..... .......(POFF and TCO from baro, read once). Result is signed 64bit(??) int. Maybe make this on 32bit. Will see how it effects precision.

    SENS = PSENS * 2^15 + (TCS * dT)/2^8......(PSENS and TCS from baro, read once). Again, 64bit result...

    P        = (ADC Reading * SENS / 2^21 - OFF)/2^15

     

    Then in flight all i'd need to do is compare p with P...

     

    So I count 1 integer mul, 1 integer div, 1 integer add, 4 FP muls, 4 FP div's, 5 FP exponentials, 2 FP adds and 1 FP subtract...

  12. Hi Enl,

     

    I have some algorithims which check if altitude is over a certain value, which is configured by the user.

    I also calculate velocity based on change in altitude and again, this velocity can be checked against a user setting. 

     

    If altitude had a predictable relationship to pressure (i.e ADC value) I could convert those user altitude/velocity values into ADC/deltaADC before the flight (or even by the configuration program on a PC) and save alot of headache.

     

    Unfortunately, the altitude/pressure relationship changes depending on the atmospheric conditions at the time of launch, and also needs to be adjusted for differing ground altitude.

     

    Maybe I could have the firmware determine these thresholds in realtime while sitting on the pad waiting for launch. It would only need to be done at a VERY low rate, and the threshold would be fixed once launch is detected and I need the headroom for the important stuff...not like the weather will change much in the very short time these rockets take to reach apogee :D

     

    This would also work for acceleration/velocity from the accelerometer, however I also have a magnetometer on board which initially I will be using to determine tilt (for safety), but ultimately I would like to integrate the magnetometer data with accelerometer to get the vertical component of velocity for no vertical flights...

     

    Any thoughts are appreciated. As usual my posts tend to wander, but I guess this is still on subject, as in the end it is optimising/reducing math :)

  13. Hi, 

     

    Thanks for the info, I have read that in detail over the last few months and will tackle Kalman filtering once I have this thing working without it first. Seeing as this is my first time using an MSP device I want to keep it as simple as possible to start with :)

  14. Since your MSP430 has a hardware multiplier, the multiply would be quicker. But modern divide function don't take too long.

     

    One interesting trick, since alot of maths (especially with ADC) will involve multiplying by a fraction. you can often factor out the divide when you use a HW multiply.

    X = Y * 2/3;  // original
    X = Y * (2*(65536/3))/(3* (65536/3)); // multiply top/bottom to get 65536 on bottom
    X = Y * (43691/65536); // the result of this adjustment.
    
    (Y * 43691); // use the HW multi for this
    X = RESHI; // take the high word
    

    The trick is to get the result stored entirely within the higher word of the result.

     

    To my knowledge, compilers wont do this.

     

    Interesting. Would this work with :

     

    Result = ADC * 0.049?

     

    and also

     

    P0 = 9085466 (max 16777216)

    ADC = something similar P0 (max 16777216)

     

    Result = P0 / ADC

     

    This is the first part of the pressure to altitude calculation with data from a 24bit barometer :)

    Well I think it is, trying to get my head around the hypsometric equations, as I want it to take into account lapse rate for altitudes over 11km and most equations stop there.

  15. Thanks guys, very helpful.

     

    I forgot to ask, is the dynamic range of single precision FP enough to hold a result which might range from -1500.00 up to 30000.00?

    Im having a bit of trouble understanding the pages ive been reading to learn about FP.

     

    For most of my results they only need 1 position before the decimal point, and max 8 after the DP, but I have a few with larger ranges. Fortunatly, I need fewer DP with those.

  16. Hi All,

     

    Hope no-one minds me bombarding the forums with these n00b questions :)

    I am writing the math for my rocket altimeter project and have some questions regarding the best way to do it.

     

    Im using CCS and MSP430FR5739 which has hardware multiply, and I have included the MSP430_math routines

     

    Lets say I need to perform the following equation (as an example)

     

    P = (D1 * SENS / 2 - OFF) / 2

    D1 = unsigned long

    SENSE = signed long

    OFF = signed long

     

    Obvious optimisations aside (e.g. D1 / 2 before the FP mult to save an FP div...), would it give me faster code to break it into parts (not as concerned about code size)

    P = SENS / 2

    P = P * D1

    P = P - OFF

    P = P / 2

    or leave it as a single equation as in the example?

     

     

    Is it faster to divide or multiply? This example is probably a bad one since div2 would be nice and easy, but lets assume I need to divide by 200 and end up with a floating point result. Would I be better off multiplying by 0.005 instead?

     

    I have enabled the hardware multiply. What is the trade off between 16 and 32 bit mult?

     

    This next one isnt really MSP430 or C related, but I still need help :) Math has never been my strong point...

     

    If n =  5.257, is x ^ (1/n) the same as x ^ (0.1902225)? Or will I need to use logarithmic math? <---This bit rings a bell from high school...

     

    0.1902225 being the result of performing 1/n

     

    Thanks again in advance!

  17. Thanks for all that! I will read the link you provided.

     

    I dont think im pushing the memory that much. I dont know how to check how big the compiled program will be?

    EDIT: Found out :)

     

    Using 1950bytes of FRAM, and 952bytes RAM. So ive only used 12% of max FRAM which is good. 

    I would say i've typed 60%-70% of the logic, but havent put any math into it yet (which will use MSP430_math library). Should have enough for that library though.

     

    The big thing which gave me memory errors was a buffer which I want to make 1840 bytes...until I realised this would be in RAM which is only 1k Bytes haha

     

    I haven't looked into it yet, but I guess there is someway I can keep this buffer in FRAM along with the program memory.

     

    Ill point out I don't have my PCB made yet, just writing this program as much as I can while I wait :) Hope its not too buggy!

  18. Hi Enl,

     

    Thanks for taking a look.

     

    i2c_start simply sets up the USCI module depending on whether im writing, reading or writing with a repeat start before reading. Should be fairly fast as there is 1 short if statment and a handful of direct register access'.

    void i2c_start(int addr, char cmd_type, int num_bytes)
    {
    	//Configure
    	command_type = cmd_type;
    	UCB0CTLW0 |= UCSWRST; // put eUSCI_B in reset state
    	UCB0TBCNT = num_bytes; // automatic stop after x bytes
    	UCB0CTLW0 &= ~UCSWRST; // eUSCI_B in operational state
    	UCB0I2CSA = addr; // address of slave without r/w bit
    
    	if (cmd_type == I2C_READ) // Read
    	{
    		UCB0CTLW0 &= !UCTR; // Put into receive mode
    	} else {
    		UCB0CTLW0 |= UCTR;  //transmitter mode
    	}
    	//Start
    	UCB0CTLW0 |= UCTXSTT; // generate start condition
    }
    
  19. Thanks, I think that makes sense. The functions being called are what I would consider short, but having no previous experience with MSP, it would be good to have your opinion.

     

     

    The following is used once within the interrupt, so I will move this inline.

    int increment(int value, int max)
    {
    value++;
    if (value == max) { value = 0; }
    return value;
    }
    
    
     
    and used 9 times (i just realised this is a bad implementation of increment, so I will re-write and inline it too :)
     
    void i2c_add_to_queue(char cmd)
    {
    i2c_queue[i2c_queue_write] = cmd;
    
    i2c_queue_write++;
    if(!(i2c_queue_write < QUEUE_LENGTH))
    {
    i2c_queue_write = 0;
    }
    }
    

    and here is the largest one, used once in the interrupt but I am using it in other places also which is why I made it a function. The only reason this is so long is because its a giant switch/case. The actual number of tasks performed is quite small. 

    void i2c_process_queue()
    {
    	switch (i2c_queue[i2c_queue_read])
    	{
    	case 1: //Accel data (write/read repeat start)
    		i2c_send_buffer[0] = 0x32; // in this case, auto stop is after reading bytes. 0x32 is the start address
    		i2c_start(0x1D, I2C_REPEATSTART, 6);
    		break;
    	case 2: //Start magneto sample (write)
    		i2c_send_buffer[0] = 0x02;
    		i2c_send_buffer[1] = 0x01;
    		i2c_start(0x1E, I2C_WRITE, 2);
    		break;
    	case 3: //Get magneto data (write/read repeat start)
    		i2c_send_buffer[0] = 0x03; // in this case, auto stop is after reading bytes. 0x03 is the start address
    		i2c_start(0x1E, I2C_REPEATSTART, 6);
    		break;
    	case 4: //Baro - start temp sample (write)
    		i2c_send_buffer[0] = 0x48; //4096 OSR
    		i2c_start(0x77, I2C_WRITE, 1);
    		break;
    	case 5: //Baro - Get temp data (read)
    		i2c_start(0x77, I2C_READ, 3);
    		break;
    	case 6: //Baro - Start pressure sample (write)
    		i2c_send_buffer[0] = 0x58; //4096 OSR
    		i2c_start(0x77, I2C_WRITE, 1);
    		break;
    	case 7: //Baro - Get temp data (read)
    		i2c_start(0x77, I2C_READ, 3);
    		break;
    	case 8: // Baro - Ready ADC
    		i2c_send_buffer[0] = 0x00;
    		i2c_start(0x1E, I2C_WRITE, 1);
    		break;
    	default: //Empty, end of queue
    		break;
    	}
    }
    

    The interrupt with the longest code consists of 8 if statment's (worst case all 8 will be entered), and in each if statement i2c_add_to_queue will be called max 3 times. Is this too long?

  20. Hi All,

     

    I'm probably getting these due to my inexperience with C, but here goes...

    Im getting the following remarks and errors during compilation.

     

    "../main.c", line 321: remark #1538-D: (ULP 10.1) ISR i2c_send_complete calls function incr. Recommend moving function call away from ISR, or inlining the function, or using pragmas

     

    I use this function to increment a pointer, and it is used mutiple times within the ISR so I dont really want to put it inline as it will take up a whole lot more code space...is this a code breaker? If it is, how do I use pragma?

     

    Im getting this with other functions too, I just used this one as an example.

     

     

  21. Oh thats something I didnt think of.

     

    Does the USCI module add the read/write bit to the end of the slave address?

    I assume it does, because the address is refered to as 7 bits, not 8. Thought i'd check because I cant change the address before the repeat start without resetting everything...

×
×
  • Create New...