Jump to content
43oh

oPossum

Members
  • Content Count

    925
  • Joined

  • Last visited

  • Days Won

    103

Posts posted by oPossum

  1. They have to compete with ARM M0+, M3, M4 and M7; plus many 4 and 8 bit parts from Asia. There is no lack of competition.

     

    TI has hurt themselves with poor management of their low end ARM chips (Stellaris, Tiva, MSP432).

     

    MSP430 will remain a great low power choice for quite some time.

  2. A variation of the RTTL player that adds a simple envelope to each note.

     

     

     

     

    Some in assembly & C:

     

    MIDI driven:

     

     

    http://forum.43oh.com/topic/810-fraunchpad-poly-synth/

     

    This has a bug that causes only half of the sine wave to be used. Look carefully at the 'scope and you will see it.

     

     

    Table driven:

     

    This has a bug that causes the frequency to be a bit off. Don't remember if I fixed the posted code.

     

     

     

    http://forum.43oh.com/topic/1729-fraunchpad-synth-still-alive/

  3. Wait for transmission of all bits to complete before latching the outputs

     

    void WriteData(unsigned char data) //SPI
    {
        UCB0TXBUF = data;                // Transmit character
        while(UCB0STAT & UCBUSY);        // Wait for all bits to finish
        P2OUT |= LATCH_BIT;              // Pulse latch
        P2OUT &= ~LATCH_BIT;
    }
    
  4. They are two distinct interrupts, you do not have to enable both.

     

    The TAIE bit in TACTL enables an interrupt that occurs when the timer reaches 0.

     

    The CCIE bit in the TACCTLx registers enables an interrupt that occurs on a match between the compare register or a capture event.

     

    All these interrupt enable bits are completely independent of each other. Enable only those that you are using and have written an ISR for.

     

    The only other interrupt that has to be enabled is the global interrupt flag in the status register. That can be enabled with _enable_interrupts() or a few other methods.

  5. If the TA0CTL line you posted isn't actually commented out, then your code may be stuck in the other Timer A interrupt (TIMER0_A1_VECTOR). That interrupt requires reading TA0IV to clear the flag. If you don't read TA0IV, it will get stuck with that ISR repeating endlessly. The fix is to remove TAIE from that line.

     

    TA0CCTL0 |= CCIE; // enable interrupt
    TA0CTL |= (TASSEL_2 + MC_1 + TAIE); // start timer, enable interrupts
    
  6. SLAU132J MSP430 Optimizing C/C++ Compiler v 4.4 User's Guide

     

    1.3 ANSI/ISO Standard

    The compiler supports both the 1989 and 1999 versions of the C language and the 2003 version of the

    C++ language. The C and C++ language features in the compiler are implemented in conformance with

    the following ISO standards:

     

  7. 
    

    // Timer A0 interrupt service routine

    #pragma vector=TIMER0_A0_VECTOR

    __interrupt void Timer_A (void)

    {

    } // <<<---- missing closing brace <<<----

     

    // Port 1 interrupt service routine

    #pragma vector=PORT1_VECTOR

    __interrupt void Port_1(void)

    {

    P2OUT ^= (BYPASS & STATUS_LED); // MAKE BYPASS AND LED HIGH

    P2IFG &= ~POSITION; // RESET INT UPON POSITION HIGH

    }

  8. The itoa() function probably takes a signed integer. On the MSP430 that has a range of -32768 to +32767. You need something that takes an unsigned integer that has a range of 0 to 65535 to get beyond the 32767 limit. The next step would be using unsigned long to go all the way to 4,294,967,295.

     

    A general purpose unsigned / unsigned long to ascii conversion can be found here:

    http://forum.43oh.com/topic/1289-tiny-printf-c-version/

     

    Here is a frequency counter that uses unsigned long to go up to 16 Mhz:

    http://forum.43oh.com/topic/1913-frequency-counter-using-launchpad-nokia-5110-lcd/

  9. A common method of printing integers uses a divide (/) and modulus (%) operation to calculate each digit. This is portable and supports any number base. The string is created in reverse order and the digit generation can easily be terminated when all significant digits have been printed, so additional logic for leading zero suppression is not needed.

     

    A much faster method uses BCD math to generate a BCD value that can then be easily convered to a string. This requires assembly or intrinsic C functions for the most efficient BCD math, so it isn't portable.

     

    The method shown here creates a fixed point binary fraction using a single division operation and then extracts the digits using bit shifts and an add. The division is unrolled and crafted to generate a result with the binary point between words to allow for efficient digit extraction. After division, the upper word contains the first digit and the lower word contains a binary fraction with all other digits. The digits are generated from the fraction by multiplying by 10. This is done with 2 shifts and an add. The result will be in the upper word. Preparation for the next digit is just a matter of clearing the upper word.

    This certainly seems like an awkward method, but it requires far less math than doing division for each digit.

     

    // Print unsigned 16 bit integer with leading zero suppression
    static void spu16(char * s, uint16_t n)
    {
    	uint16_t d = 10000 << 2;
    	uint32_t r = 0;
    	if (n >= d) n -= d, r |= (1 << 18); d >>= 1;
    	if (n >= d) n -= d, r |= (1 << 17); n <<= 1;
    	if (n >= d) n -= d, r |= (1 << 16); n <<= 1;
    	if (n >= d) n -= d, r |= (1 << 15); n <<= 1;
    	if (n >= d) n -= d, r |= (1 << 14); n <<= 1;
    	if (n >= d) n -= d, r |= (1 << 13); n <<= 1;
    	if (n >= d) n -= d, r |= (1 << 12); n <<= 1;
    	if (n >= d) n -= d, r |= (1 << 11); n <<= 1;
    	if (n >= d) n -= d, r |= (1 << 10); n <<= 1;
    	if (n >= d) n -= d, r |= (1 <<  9); n <<= 1;
    	if (n >= d) n -= d, r |= (1 <<  8); n <<= 1;
    	if (n >= d) n -= d, r |= (1 <<  7); n <<= 1;
    	if (n >= d) n -= d, r |= (1 <<  6); n <<= 1;
    	if (n >= d) n -= d, r |= (1 <<  5); n <<= 1;
    	if (n >= d) n -= d, r |= (1 <<  4); n <<= 1;
    	if (n >= d) n -= d, r |= (1 <<  3); n <<= 1;
    	if (n >= d) n -= d, r |= (1 <<  2);
    	r += (1 << 2);
    
    	unsigned c, z;
    	c = z = (r >> 16);
    	unsigned i = 4;
    	do {
    		if (z || c) *s++ = z = ('0' + c);
    		r &= 0xFFFF;
    		r <<= 1;
    		r += (r << 2);
    		c = (r >> 16);
    	} while (--i);
    	*s++ = '0' + c;
    	*s = 0;
    }
    

    When a 32 bit hardware multiplier is available, the code can be modified to multiply by the reciprocal rather than divide. The multiplication by 10 is now explicit to also take advantage of the hardware multiplier.

    static void spu16(char * s, uint16_t n)
    {
    	uint32_t r = ((53687UL * n) >> 13) + (1 << 2);
    
    	unsigned c, z;
    	c = z = (r >> 16);
    	unsigned i = 4;
    	do {
    		if (z || c) *s++ = z = ('0' + c);
    		r = (r & 0xFFFF) * 10;
    		c = (r >> 16);
    	} while (--i);
    	*s++ = '0' + c;
    	*s = 0;
    }
    
  10. The most accurate results will be obtained if the counter is never stopped or reset. The time interval is calculated by subtracting the previous capture from the current capture when the capture interrupt occurs. Refer to 17.2.4.1 (capture mode) and 17.2.2.1 (external clock source) of slau356a.

     

     

    void timer_capture_isr(void)
    {
        static int16_t previous_capture;
    
        int16_t const timer_capture = (int16_t)TAxCCRn;
    
        int16_t const error = timer_capture - previous_capture + 27008;
    
        previous_capture = timer_capture;
    
        // do something with error
    }
    
  11. Use the VCO as an external timebase for the counter. Use the GPS PPS as a timer capture interrrupt.

     

    The ISR for the timer capture interrupt will subtract the current capture from the previous to determine the VCO frequency. The DAC can then be adjusted using that value and a suitable control loop such as a PID.

  12. Printf supports the %e, %f and %g format specifiers for printing floating point numbers. Due to the automatic type promotion of varadic functions in C, the printf code must always print double precision floating point. This makes printing single precision floating point numbers slower than optimal. The precision rounding done by printf also imposes a speed penalty. The code presented here will print single precision floating point numbers much faster than printf - up to 75 times faster. It allows the number of significant digits to be 3 to 8 (a maximum of 7 is recommended). The printed number will be normalized to the range to 1.0 to less than 1000.0 and the appropriate SI prefix appended. This is similar to what the printf %e format does (1.0 to less than 10.0), but a bit easier to interpret. The full range of single precision float can not be represented by SI prefixes, so very small and very large numbers will have '?' as the prefix. This code is intended for display only. It should not be used to store values in a file for later conversion back to float due to limitations in rounding and range.

     

    A brief explanation of the code.

    Do a bitwise conversion of the float to a 32 bit unsigned integer. This is done with by getting the address of the float, casting to an unsigned integer pointer, and then dereferencing the pointer. Simply casting to an unsigned integer would not produce a bitwise copy.

        uint32_t s = *(uint32_t *)&f;
    
    The msb contains the sign flag. Append a '-' to the string if the floating point number is negative.

        if (s & (1UL << 31)) *a++ = '-';
    
    Extract the 8 bit exponent.

        int e = (s >> 23) & 0xFF;
    
    Move the significand to the upper 24 bits. Set the msb to 0.

        s <<= 8; s &= ~(1UL << 31);
    
    An exponent of 255 is used for special values of NaN (not a number) and infinity. Handle these special cases and return.

        if (e == 255) {
            if (s) {
                strcpy(a, "NaN");
            } else {
                strcpy(a, "Inf");
            }
            return;
    
    An exponent of 0 is used to represent a value of 0 and for denormals. A value of 0 is handled by setting the exponent to 127 - the same exponent used to represent 1.0, and leaving the significand as 0. Denormal numbers do not have the implicit msb of 1, so they are normalized by shifting until the leading 1 is in the msb position.

        } else if (e == 0) {
            if (s) {
                e = 1;
                while (!(s & (1UL << 31))) s <<= 1, --e;
            } else {
                e = 127;
            }
    
    If the exponent is some other value, then set the msb of the significand.

        } else {
            s |= (1UL << 31);
        }
    
    Setup a pointer to the SI prefix. This will be adjusted as the value is normalized.

        char const * sp = "???????yzafpnum kMGTPEZY????" + 15;
    
    If the value is less than 1.0 it must be multiplied by 1000 until it is 1.0 or greater. Multiplication by 1000 is done by an implicit multiply by 1024 and then subtracting a multiply by 16 and a multiply by 8.

        if (e < 127) {
            do {
                s = s - (s >> 6) - (s >> 7);
                if (!(s & (1UL << 31))) s <<= 1, --e;
                e += 10;
                --sp;
            } while (e < 127);
    
    If the value is 1000.0 or more it must be divided by 1000 until it is less than 1000.0. An unrolled floating point divide is used for maximum speed.

        } else if (e > 135) {
            while (e > (126 + 10) || (e == (126 + 10) && s >= (1000UL << (32 - 10)))) {
                uint32_t n = s;
                s = 0;
                uint32_t d = 1000UL << (32 - 10);
                if (n >= d) n -= d, s |= (1UL << 31); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 30); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 29); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 28); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 27); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 26); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 25); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 24); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 23); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 22); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 21); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 20); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 19); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 18); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 17); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 16); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 15); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 14); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 13); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 12); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 11); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 10); d >>= 1;
                if (n >= d) n -= d, s |= (1UL <<  9); d >>= 1;
                if (n >= d) n -= d, s |= (1UL <<  8); d >>= 1;
                if (n >= d) s += (1UL << 8);
                if (!(s & (1UL << 31))) s <<= 1, --e;
                e -= 9;
                ++sp;
            }
    
    The divide code is quite time consuming, so it would be advantageous to quickly reduce very large numbers. A divide by 1,000,000,000,000 is used to improve performance for these large numbers.

    The preceding multiply code could do the same for very small numbers, but there is no speed advantage due to the multiply by 1000 using 2 shift/subtract operations and multiply by lager values requiring more than 2 per 1000.

            while (e > (150 + 16) || (e == (150 + 16) && s > (999999995904ULL >> 16))) {
                uint64_t n = s;
                n <<= 32;
                s = 0;
                uint64_t d = 1000000000000ULL << (64 - 40);
                if (n >= d) n -= d, s |= (1UL << 31); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 30); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 29); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 28); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 27); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 26); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 25); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 24); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 23); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 22); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 21); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 20); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 19); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 18); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 17); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 16); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 15); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 14); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 13); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 12); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 11); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 10); d >>= 1;
                if (n >= d) n -= d, s |= (1UL <<  9); d >>= 1;
                if (n >= d) n -= d, s |= (1UL <<  8); //d >>= 1;
                //if (n >= d) s += (1UL << 8);
                if (n) s += (1UL << 8);
                if (!(s & (1UL << 31))) s <<= 1, --e;
                e -= 39;
                sp += 4;
            }
    
    Rounding is the most difficult part of printing floating point numbers. Precalculated float constants are applied based on the value of the float and the specified number of significant digits. This simple method is fast and allows for good results for up to 7 significant digits.

    typedef struct {
        uint32_t s;
        int e;
    } TFR;
    
    TFR const r[] = {
        0x800000UL << 7, 126 + 1,	// 0.5
        0xCCCCCDUL << 7, 122 + 1,	// 0.05
        0xA3D70AUL << 7, 119 + 1,	// 0.005
        0x83126FUL << 7, 116 + 1,	// 0.0005
        0xD1B717UL << 7, 112 + 1,	// 0.00005
        0xA7C5ACUL << 7, 109 + 1,	// 0.000005
        0x8637BDUL << 7, 106 + 1,	// 0.0000005
        0xD6BF95UL << 7, 102 + 1	// 0.00000005
    };
    
        if (d < 3) d = 3; else if (d > 8) d = 8;
        if (s) {
            TFR const *pr = &r[d - 3];
            if (e < (126 + 4) || (e == (126  + 4) && s < (10UL << (32 - 4)))) {			// < 10
                pr += 2;
            } else if (e < (126 + 7) || (e == (126 + 7) && s < (100UL << (32 - 7)))) {	// < 100
                ++pr;
            }
            s += (pr->s >> (e - pr->e));
            if (e == (126 + 10) && s >= (1000UL << (32 - 10))) s = (1UL << 31), e = 127, ++sp;
            else if (!(s & (1UL << 31))) s >>= 1, s |= (1UL << 31), ++e;
        }
    
    The integer part is printed using iterative subtraction of base 10 constants. This is typically faster than the common divide/modulus method.

        unsigned i = s >> 16;
        i >>= (136 - e);
        unsigned id = 1;
        char c;
        if (i >= (100 << 6)) {
            ++id; c = '0';
            while (i >= (100 << 6)) i -= (100 << 6), ++c;
            *a++ = c;
        }
        if (id == 2 || i >= (10 << 6)) {
            ++id; c = '0';
            while (i >= (10 << 6)) i -= (10 << 6), ++c;
            *a++ = c;
        }
        c = '0';
        while (i >= (1 << 6)) i -= (1 << 6), ++c;
        *a++ = c;
    
    The fractional part is printed by iterative multiplication by 10.

        *a++ = '.';
        if (e < 130) s >>= (130 - e); else s <<= (e - 130);
        d -= id;
        while (d) {
            s &= ((1UL << 28) - 1);
            s = (s << 3) + (s << 1);
            *a++ = '0' + (s >> 28);
            --d;
        }
    
    The SI prefix is appended and the string is terminated.

        *a++ = *sp;
        *a = 0;
    
    The resulting performance increase was more than I expected.

     

               TI 4.4.4         GCC 4.9.1
    ---------------------------------------
    %e       16402  6.47 s    non-functional
    %f       16380  5.78 s    non-functional
    %g       16402  4.69 s    non-functional
    ftoas(7)  8480  0.12 s    11892  0.27 s
    ftoas(3)  8480  0.09 s    11892  0.17 s
    
    Results of the test code using ftoas(7), %e, %g, and %f

    0.000000  0.000000e+00 0 0.000000
    1.401298? 0.000000e+00 0 0.000000
    1.401298? 0.000000e+00 0 0.000000
    9.809089? 0.000000e+00 0 0.000000
    99.49219? 0.000000e+00 0 0.000000
    1.000527? 0.000000e+00 0 0.000000
    9.999666? 0.000000e+00 0 0.000000
    99.99946? 0.000000e+00 0 0.000000
    1.000000? 0.000000e+00 0 0.000000
    12.00000? 1.200000e-38 1.2e-38 0.000000
    100.0000? 1.000000e-37 1e-37 0.000000
    1.000000? 1.000000e-36 1e-36 0.000000
    10.00000? 1.000000e-35 1e-35 0.000000
    100.0000? 1.000000e-34 1e-34 0.000000
    1.000000? 1.000000e-33 1e-33 0.000000
    10.00000? 1.000000e-32 1e-32 0.000000
    100.0000? 1.000000e-31 1e-31 0.000000
    1.000000? 1.000000e-30 1e-30 0.000000
    10.00000? 1.000000e-29 1e-29 0.000000
    100.0000? 1.000000e-28 1e-28 0.000000
    1.000000? 1.000000e-27 1e-27 0.000000
    10.00000? 1.000000e-26 1e-26 0.000000
    100.0000? 1.000000e-25 1e-25 0.000000
    1.000000y 1.000000e-24 1e-24 0.000000
    10.00000y 1.000000e-23 1e-23 0.000000
    100.0000y 1.000000e-22 1e-22 0.000000
    1.000000z 1.000000e-21 1e-21 0.000000
    10.00000z 1.000000e-20 1e-20 0.000000
    100.0000z 1.000000e-19 1e-19 0.000000
    1.000000a 1.000000e-18 1e-18 0.000000
    10.00000a 1.000000e-17 1e-17 0.000000
    100.0000a 1.000000e-16 1e-16 0.000000
    1.000000f 1.000000e-15 1e-15 0.000000
    10.00000f 1.000000e-14 1e-14 0.000000
    100.0000f 1.000000e-13 1e-13 0.000000
    1.000000p 1.000000e-12 1e-12 0.000000
    10.00000p 1.000000e-11 1e-11 0.000000
    100.0000p 1.000000e-10 1e-10 0.000000
    1.000000n 1.000000e-09 1e-09 0.000000
    10.00000n 1.000000e-08 1e-08 0.000000
    100.0000n 1.000000e-07 1e-07 0.000000
    1.000000u 1.000000e-06 1e-06 0.000001
    10.00000u 1.000000e-05 1e-05 0.000010
    100.0000u 1.000000e-04 0.0001 0.000100
    1.000000m 1.000000e-03 0.001 0.001000
    10.00000m 1.000000e-02 0.01 0.010000
    100.0000m 1.000000e-01 0.1 0.100000
    1.000000  1.000000e+00 1 1.000000
    1.234568  1.234568e+00 1.23457 1.234568
    10.00000  1.000000e+01 10 10.000000
    100.0000  1.000000e+02 100 100.000000
    1.000000k 1.000000e+03 1000 1000.000000
    10.00000k 1.000000e+04 10000 10000.000000
    100.0000k 1.000000e+05 100000 100000.000000
    1.000000M 1.000000e+06 1e+06 1000000.000000
    10.00000M 1.000000e+07 1e+07 10000000.000000
    100.0000M 1.000000e+08 1e+08 100000000.000000
    1.000000G 1.000000e+09 1e+09 1000000000.000000
    10.00000G 1.000000e+10 1e+10 10000000000.000000
    100.0000G 1.000000e+11 1e+11 99999997952.000010
    1.000000T 1.000000e+12 1e+12 999999995903.999925
    10.00000T 1.000000e+13 1e+13 9999999827968.000174
    100.0000T 1.000000e+14 1e+14 100000000376832.008362
    1.000000P 1.000000e+15 1e+15 999999986991104.125977
    10.00000P 1.000000e+16 1e+16 10000000272564222.812653
    100.0000P 1.000000e+17 1e+17 99999998430674934.387207
    1.000000E 1.000000e+18 1e+18 999999984306749343.872070
    10.00000E 1.000000e+19 1e+19 9999999980506448745.727539
    100.0000E 1.000000e+20 1e+20 100000002004087710380.554199
    1.000000Z 1.000000e+21 1e+21 1000000020040877103805.541992
    10.00000Z 1.000000e+22 1e+22 9999999778196308612823.486328
    100.0000Z 1.000000e+23 1e+23 99999997781963086128234.863281
    1.000000Y 1.000000e+24 1e+24 1000000013848427772521972.656250
    10.00000Y 1.000000e+25 1e+25 9999999562023527622222900.390625
    100.0000Y 1.000000e+26 1e+26 100000002537764322757720947.265625
    1.000000? 1.000000e+27 1e+27 999999988484154701232910156.250000
    10.00000? 9.999999e+27 1e+28 9999999442119691371917724609.375000
    100.0000? 1.000000e+29 1e+29 100000001504746651649475097656.250000
    1.000000? 1.000000e+30 1e+30 1000000015047466516494750976562.500000
    10.00000? 1.000000e+31 1e+31 9999999848243210315704345703125.000000
    100.0000? 1.000000e+32 1e+32 100000003318135333061218261718750.000000
    1.000000? 1.000000e+33 1e+33 999999994495727896690368652343750.000000
    10.00000? 1.000000e+34 1e+34 9999999790214771032333374023437500.000000
    100.0000? 1.000000e+35 1e+35 100000004091847860813140869140625000.000000
    1.000000? 1.000000e+36 1e+36 999999961690316438674926757812500000.000000
    10.00000? 1.000000e+37 1e+37 9999999933815813064575195312500000000.000000
    100.0000? 1.000000e+38 1e+38 99999996802856898307800292968750000000.000000
    340.0001? 3.400000e+38 3.4e+38 339999995214436411857604980468750000000.000000
    NaN nan nan nan
    Inf +inf +inf +inf
    
    Complete code with test case.

    #include <msp430.h> 
    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>
    #include <math.h>
    
    static void print(char const *s)
    {
        while(*s) {
            while(!(UCA1IFG & UCTXIFG));
            UCA1TXBUF = *s++;
        }
    }
    
    typedef struct {
        uint32_t s;
        int e;
    } TFR;
    
    TFR const r[] = {
        0x800000UL << 7, 126 + 1,	// 0.5
        0xCCCCCDUL << 7, 122 + 1,	// 0.05
        0xA3D70AUL << 7, 119 + 1,	// 0.005
        0x83126FUL << 7, 116 + 1,	// 0.0005
        0xD1B717UL << 7, 112 + 1,	// 0.00005
        0xA7C5ACUL << 7, 109 + 1,	// 0.000005
        0x8637BDUL << 7, 106 + 1,	// 0.0000005
        0xD6BF95UL << 7, 102 + 1	// 0.00000005
    };
    
    void ftoas(char *a, float const f, unsigned d)
    {
        uint32_t s = *(uint32_t *)&f;
        if (s & (1UL << 31)) *a++ = '-';
        int e = (s >> 23) & 0xFF;
        s <<= 8; s &= ~(1UL << 31);
    
        if (e == 255) {
            if (s) {
                strcpy(a, "NaN");
            } else {
                strcpy(a, "Inf");
            }
            return;
        } else if (e == 0) {
            if (s) {
                e = 1;
                while (!(s & (1UL << 31))) s <<= 1, --e;
            } else {
                e = 127;
            }
        } else {
            s |= (1UL << 31);
        }
    
        char const * sp = "???????yzafpnum kMGTPEZY????" + 15;
        if (e < 127) {
            do {
                s = s - (s >> 6) - (s >> 7);
                if (!(s & (1UL << 31))) s <<= 1, --e;
                e += 10;
                --sp;
            } while (e < 127);
        } else if (e > 135) {
            while (e > (150 + 16) || (e == (150 + 16) && s > (999999995904ULL >> 16))) {
                uint64_t n = s;
                n <<= 32;
                s = 0;
                uint64_t d = 1000000000000ULL << (64 - 40);
                if (n >= d) n -= d, s |= (1UL << 31); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 30); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 29); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 28); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 27); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 26); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 25); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 24); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 23); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 22); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 21); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 20); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 19); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 18); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 17); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 16); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 15); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 14); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 13); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 12); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 11); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 10); d >>= 1;
                if (n >= d) n -= d, s |= (1UL <<  9); d >>= 1;
                if (n >= d) n -= d, s |= (1UL <<  8); //d >>= 1;
                //if (n >= d) s += (1UL << 8);
                if (n) s += (1UL << 8);
                if (!(s & (1UL << 31))) s <<= 1, --e;
                e -= 39;
                sp += 4;
            }
            while (e > (126 + 10) || (e == (126 + 10) && s >= (1000UL << (32 - 10)))) {
                uint32_t n = s;
                s = 0;
                uint32_t d = 1000UL << (32 - 10);
                if (n >= d) n -= d, s |= (1UL << 31); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 30); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 29); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 28); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 27); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 26); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 25); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 24); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 23); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 22); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 21); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 20); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 19); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 18); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 17); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 16); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 15); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 14); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 13); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 12); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 11); d >>= 1;
                if (n >= d) n -= d, s |= (1UL << 10); d >>= 1;
                if (n >= d) n -= d, s |= (1UL <<  9); d >>= 1;
                if (n >= d) n -= d, s |= (1UL <<  8); d >>= 1;
                if (n >= d) s += (1UL << 8);
                if (!(s & (1UL << 31))) s <<= 1, --e;
                e -= 9;
                ++sp;
            }
        }
    
        if (d < 3) d = 3; else if (d > 8) d = 8;
        if (s) {
            TFR const *pr = &r[d - 3];
            if (e < (126 + 4) || (e == (126  + 4) && s < (10UL << (32 - 4)))) {        // < 10
                pr += 2;
            } else if (e < (126 + 7) || (e == (126 + 7) && s < (100UL << (32 - 7)))) { // < 100
                ++pr;
            }
            s += (pr->s >> (e - pr->e));
            if (e == (126 + 10) && s >= (1000UL << (32 - 10))) s = (1UL << 31), e = 127, ++sp;
            else if (!(s & (1UL << 31))) s >>= 1, s |= (1UL << 31), ++e;
        }
    
        unsigned i = s >> 16;
        i >>= (136 - e);
        unsigned id = 1;
        char c;
        if (i >= (100 << 6)) {
            ++id; c = '0';
            while (i >= (100 << 6)) i -= (100 << 6), ++c;
            *a++ = c;
        }
        if (id == 2 || i >= (10 << 6)) {
            ++id; c = '0';
            while (i >= (10 << 6)) i -= (10 << 6), ++c;
            *a++ = c;
        }
        c = '0';
        while (i >= (1 << 6)) i -= (1 << 6), ++c;
        *a++ = c;
    
        *a++ = '.';
    
        if (e < 130) s >>= (130 - e); else s <<= (e - 130);
    
        d -= id;
        while (d) {
            s &= ((1UL << 28) - 1);
            s = (s << 3) + (s << 1);
            *a++ = '0' + (s >> 28);
            --d;
        }
    
        *a++ = *sp;
        *a = 0;
    }
    
    
    #define smclk_freq  (32768UL * 31UL)            // SMCLK frequency in hertz
    #define bps         (9600UL)                    // Async serial bit rate
    
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;                   // Stop watchdog timer
                                                    //
        P4SEL = BIT4 | BIT5;                        // Enable UART pins
        P4DIR = BIT4 | BIT5;                        //
                                                    //
                                                    // Initialize UART
        UCA1CTL1 = UCSWRST;                         // Hold USCI in reset to allow configuration
        UCA1CTL0 = 0;                               // No parity, LSB first, 8 bits, one stop bit, UART (async)
        const unsigned long brd = (smclk_freq + (bps >> 1)) / bps;  // Bit rate divisor
        UCA1BR1 = (brd >> 12) & 0xFF;               // High byte of whole divisor
        UCA1BR0 = (brd >> 4) & 0xFF;                // Low byte of whole divisor
        UCA1MCTL = ((brd << 4) & 0xF0) | UCOS16;    // Fractional divisor, oversampling mode
        UCA1CTL1 = UCSSEL_2;                        // Use SMCLK for bit rate generator, release reset
        
        char s[32], t[96];
    
        float const tv[] = {
            0.0f,
            7.1e-46f,
            1.0e-45f,
            1.0e-44f,
            1.0e-43f,
            1.0e-42f,
            1.0e-41f,
            1.0e-40f,
            1.0e-39f,
            1.2e-38f,
            1.0e-37f,
            1.0e-36f,
            1.0e-35f,
            1.0e-34f,
            1.0e-33f,
            1.0e-32f,
            1.0e-31f,
            1.0e-30f,
            1.0e-29f,
            1.0e-28f,
            1.0e-27f,
            1.0e-26f,
            1.0e-25f,
            1.0e-24f,
            1.0e-23f,
            1.0e-22f,
            1.0e-21f,
            1.0e-20f,
            1.0e-19f,
            1.0e-18f,
            1.0e-17f,
            1.0e-16f,
            1.0e-15f,
            1.0e-14f,
            1.0e-13f,
            1.0e-12f,
            1.0e-11f,
            1.0e-10f,
            1.0e-9f,
            1.0e-8f,
            1.0e-7f,
            0.000001f,
            0.00001f,
            0.0001f,
            0.001f,
            0.01f,
            0.1f,
            1.0f,
            1.23456789f,
            10.0f,
            100.0f,
            1000.0f,
            10000.0f,
            100000.0f,
            1000000.0f,
            10000000.0f,
            100000000.0f,
            1000000000.0f,
            1.0e10f,
            1.0e11f,
            1.0e12f,
            1.0e13f,
            1.0e14f,
            1.0e15f,
            1.0e16f,
            1.0e17f,
            1.0e18f,
            1.0e19f,
            1.0e20f,
            1.0e21f,
            1.0e22f,
            1.0e23f,
            1.0e24f,
            1.0e25f,
            1.0e26f,
            1.0e27f,
            1.0e28f,
            1.0e29f,
            1.0e30f,
            1.0e31f,
            1.0e32f,
            1.0e33f,
            1.0e34f,
            1.0e35f,
            1.0e36f,
            1.0e37f,
            1.0e38f,
            3.4e38f,
            NAN,
            INFINITY
        };
    
        TA0EX0 = 7;
        TA0CTL = TASSEL_2 | ID_3 | MC_2;
        TA0CTL |= TACLR;
    
        unsigned i;
        for (i = 0; i < sizeof(tv) / sizeof(tv[0]); ++i) {
            float const f = tv[i];
            ftoas(s, f, 7);
            //print(s); print("\r\n");
            //sprintf(t, "%e", f);
            //sprintf(t, "%f", f);
            //sprintf(t, "%g", f);
            //sprintf(t, "%e %f %g %s\r\n", f, f, f, s);
            sprintf(t, "%s %e %g %f\r\n", s, f, f, f);
            print(t);
        }
    
        volatile float et = ((float)TA0R + ((TA0CTL & TAIFG) ? 65536.0 : 0.0)) * 63.0f / 1000000.0f; // Elapsed time in microseconds
        ftoas(t, et, 5);
        //sprintf(t, "%f", et);
        print(t); print("s\r\n");
    
        for(;;
    
        return 0;
    }
    
  13. This is obviously wrong:

     

     UCSCTL2 |= 499;                           // Set DCO Multiplier for 16MHz
                                                // (N + 1) * FLLRef = Fdco
                                                // (499 + 1) * 32768 = 16MHz
    
    change to...

     

     UCSCTL2 |= 499;                           // Set DCO Multiplier for 16MHz
                                                // (N + 1) * FLLRef = Fdco
                                                // (499 + 1) * 32768 = 16.384 MHz
    
    and also change...

     

     const unsigned long smclk_freq = 16384000UL; // SMCLK frequency in hertz
    
    and delete (or fix and make use of)...

     

    /*******************************************************************************
     *
     ******************************************************************************/
    #define F_CPU 16000000UL
    #define BAUD 19200
    #define BAUD_PRESCALE (((F_CPU / (BAUD * 16UL))) - 1)
    
×
×
  • Create New...