43oh # oPossum

Members

925

103

## Reputation Activity

1. oPossum reacted to mprairie in Interface MSP430 and MPU6050
This is a little late to the topic, but hopefully it will help the next time it comes up in a search...

The key to success with the MPU-6050 module that I got from Amazon (about \$4 US) was to use a 5V source for the board's Vcc.  It has a 3.3V regulator on board to convert the 5V from Arduino to 3.3V required, and the LaunchPad's 3.3V Vcc was not enough.  The module also contains pull-up resistors for SCL and SDA, and 330-Ohm resistors on the SCL and SDA lines as well.  I was able to connect the LaunchPad GND, SCL (P1.6) and SDA (P1.7) directly to the module, but powered the module separately with a 5V source, and it worked fine.

I adapted some code from the TI examples that use the USCIAB0TX_VECTOR interrupt service routine when UCB0RXIFG or UCB0TXIFG is set.

Mike
2. Hi,

Having a nice matrix led display laying around with no use of I assembled a test circuit with launchpad and modified the code of @simpleavr to run on it.

The display is driven by four MAX7219 chips chained on SPI bus. I noticed that the only floating point operation that your code was using is a square root operation in line 257. Once I added a fixed-point square root routine, linking with math lib is not necessary anymore - spared a lot of flash space. The fixed-point routine is also 3 times faster than mathlib floating point one: 50us vs 150us
#ifdef FLOATING_POINT // sqrt: 150us #include <math.h> #else // FLOATING_POINT // 50us unsigned char sqrt16(unsigned short a) { unsigned short rem = 0, root = 0; int i; for(i = 0; i < 8; ++i) { root <<= 1; rem = ((rem << 2) + (a >> 14)); a <<= 2; ++root; if(root <= rem) { rem -= root; ++root; } else { --root; } } return (unsigned char)(root >> 1); } #endif // FLOATING_POINT Further I've added Hamm windowing to minimize spectral leakage:
// scilab 255 * window('kr',64,6) //const unsigned short hamming = { 4, 6, 9, 13, 17, 23, 29, 35, 43, 51, 60, 70, 80, 91, 102, 114, 126, 138, 151, 163, 175, 187, 198, 208, 218, 227, 234, 241, 247, 251, 253, 255 }; // scilab 255 * window('kr',64,4) const unsigned short hamming = { 23, 29, 35, 42, 50, 58, 66, 75, 84, 94, 104, 113, 124, 134, 144, 154, 164, 174, 183, 192, 201, 210, 217, 224, 231, 237, 242, 246, 250, 252, 254, 255 }; // scilab 255 * window('kr',64,2) //const unsigned short hamming = { 112, 119, 126, 133, 140, 147, 154, 161, 167, 174, 180, 186, 192, 198, 204, 209, 214, 219, 224, 228, 232, 236, 239, 242, 245, 247, 250, 251, 253, 254, 255, 255 }; Applying windowing on 32 samples uses fixed point math:
for (i=0;i<Nx;i++) { int hamm = hamming[i<(FFT_SIZE-1)?i:(Nx-1)-i] * data[i]; data[i] = (hamm >> 8); } Finally the display buffer is filled in with output of FFT function:
unsigned long mask = 1UL;         for (i=0; i<32; ++i, mask <<= 1) {             for(j=0;j<8;++j) {                 if(j<plot[i])                     dbuff.ulongs[j] |= mask;                 else                     dbuff.ulongs[j] &= ~(mask);             }         } where dbuff is display buffer organized as:
typedef union { unsigned long longs; unsigned int ints; unsigned char chars; } longbytes; union { unsigned char bytes[8*4]; longbytes lbytes; unsigned long ulongs; } dbuff; which make it easy to manipulate:
unsigned char spibuff; void SPI_Write(unsigned char* array) { P2OUT &= ~LED_CS; __delay_cycles(50); unsigned int h = 8; while(h) { UCB0TXBUF = *array; while (UCB0STAT & UCBUSY); ++array; --h; } P2OUT |= LED_CS; } void update_display() { unsigned char i; for(i = 0; i < 8; ++i) { spibuff = spibuff = spibuff = spibuff = i+1; spibuff = dbuff.lbytes[i].chars; spibuff = dbuff.lbytes[i].chars; spibuff = dbuff.lbytes[i].chars; spibuff = dbuff.lbytes[i].chars; SPI_Write(spibuff); } } BTW I got a second 8x32 led matrix displays from the same ebay offer, and it turned out to be mirrored - LED matrix is turned around 180deg, so the update_display() routine for the other one have to push bytes in order 0 through 3, and bit-shift operations ( << and >> ) yield opposite display reaction (left vs right scroll).

https://youtu.be/Nen6yd5kvZs

s.

Edit: correct photo attachement and source code snippets
led_fft.tar.bz2
3. oPossum got a reaction from MSPLife in MSP430 + 74HC595 trouble
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. Did not have enough parts to assemble an entire panel. I've done 2 boards.

Seems to work as expected! I am currently adjusting the brightness by a PWM into Output enable.

The new PCB does not feature a MCU. It has a breakout for the major signals the display needs
Serial IN Serial Clock Data Latch Output Enable Reset Vcc Gnd This means to complete this clock I will need a second daughter board. I deferred getting it fabbed because I had not designed it. This is the next step. I also need to decide if I want a dedicated RTC. Or maybe a GPS?! (I like the idea of not needing to set time..

Having the controller board separate means I can potentially make a more advanced control PCB, maybe an ESP8266? Pulls down internet time.
5. oPossum got a reaction from ElTita in Flash memory can be damaged by writes? (and related things)
Flash will wear out after being erased and written many times. As a practical matter you will have to keep the pointer to the flash in RAM.

This would be a good application for one of the FRAM MSP430s. They have essentially unlimited write endurance.
6. oPossum got a reaction from tripwire in Flash memory can be damaged by writes? (and related things)
Flash will wear out after being erased and written many times. As a practical matter you will have to keep the pointer to the flash in RAM.

This would be a good application for one of the FRAM MSP430s. They have essentially unlimited write endurance.
7. This project is a submission for the 2015 Project of the Month Halloween contest.  It came about as a request from my four year old grandson after he had seen the Blue Angels fly over during Seafair in Seattle.

The basic air frame was constructed from two cardboard boxes as shown in the photograph below.
.
The boxes are attached to each other with brads and hot glue.  Edges are reinforced where I felt necessary by folding extra cardboard over or gluing in reinforcement cardboard.  Also shown in the photograph above are the following:
wings, tail, and fins constructed from a corrugated plastic storage box and hot glued in place reflector on the nose constructed from a coffee can bottom which will eventually become the "search light".  There is a similar reflector on the tail which will become the jet exhaust. control panel with various switches and a potentiometer I had in my junk box installed on a wooden paint stirring stick The visible surfaces were then covered with wrapping paper using Outdoor Mod Podge - a waterbased sealer, glue and finish available in craft stores in the United States.  A second coat was then put on to make it a bit more waterproof.

This is the schematic for the avionics.

A little custom MSP430G2553 board with two AA batteries beside it in the tail controls an Adafruit neopixel ring "jet exhaust" with a toggle switch on the panel to turn it on and off.  Everything else runs off of three AA batteries with the wiring in the front of the aircraft between a cardboard firewall and the nose.  Two latching buttons turn colored LEDs on the panel on and off while a third turns a 3W LED (searchlight) on and off.  There is a potentiometer to control the brightness of the searchlight.  Finally I repurposed the sound board and speaker from an old greeting card that was originally powered by a coin cell.

The WS2812 Adafruit Neopixel ring is controlled by the MSP430G2553. I used the library posted by ILAMtitan at 43oh - so full credit to those who had a hand in developing it.  The library example worked well as is for my purposes and about the only thing I changed was the output pin and the number of pixels being controlled in the code.

Here is a picture of my grandson trying it out. We glued plastic cups over the headlight and jet exhaust and stuck Energia stickers on it.  I may touch it up a bit more if I have time and post a final picture.

Improvement Ideas:  I also made a "candy counter" out of an old scale for his entertainment (and mine).  His immediate reaction was that we should somehow attach the candy counter to the airplane.  Clever, but not practical due to the need for the scale to be level and not banged around by a four year old.  Using a counter where candy is funneled past a beam, like Chicken did with his counter might work though.  My idea is that we add GPS along with thumbs up/down buttons.  Then he could rate offerings and either store the data as a reminder for next year or send it out over the IOT with location so that his buddies know where the good candy is.
8. MSP-FET MSP430 Flash Emulation Tool

Use coupon code 60WOW on the TI-EStore.

9. oPossum reacted to terjeio in Multimedia Center
My (crazy) project is getting closer to completion so time to start a project topic. I have verified my Tiva C based controller design and are now waiting for PCBs - will arrive from China in a few days.

My background is from Radio/TV servicing and medical electronics, but for the last 25 years I have mainly been working on a large database application written in OpenEdge. Two years ago my preamp that I made some 30 years ago started to fail due to the rubber based switches rotting (a bit like my brain these days...). Since I did not want to buy one I decided to make a new - again with no mechanical parts in the audio path. A lot has happened since back when I was involved in electronics, and I have spent some time doing research for what components are now available - to many one may argue.

I decided to use a CPLD programmed in VHDL for the switching logic, high quality analog switches (my original design employed 40 series CMOS for these) and a VCA (voltage controlled amplifier) for volume control. I did not want to introduce a MCU because I believed I would get into trouble with the clock signal interfering with the audio... Anyway, my new design was successful and has now been in service for nearly two years.

After doing this I took an interest in learning about microprocessors again, I started out with Atmel/Ardouino and Energia but I found that combination a bit lacking - no easy way to do debugging was a showstopper for me. I found the TI processors more appealing, CCS allows me to get my hands dirty on "bare metal" and a decent debugger makes life easier.

So, here I am making another iteration of my preamp - this time involving no less than four TI processors. I have decided to post my project under the Tiva C header since it is the main workhorse, but the three other MCUs are 430s.

Ok, enough rambling - here are the main components I have designed:

Raspberry PI power switch - PC-style startup/shutdown, may be controlled over I2C or from a front panel switch.

IR Remote Control - RC5 protocol.

Main controller - Tiva C based, custom UI library and support for Keystone DAB radio.

Preamp board, 5 line inputs with the option of switcing one to phono (magnetic cartridge - vinyl is getting popular again), DAB option, I2C control and still a VCA based volume control.

I have recently switched to KiCad as my EDA, I did use Zenith PCB earlier but I am a bit scared to continue using that as it is licensed on a yearly basis (even if it is free) - who knows when it wil not be supported anymore. KiCad is open software and does not suffer from any limitations to number of pins or board size.

Attached are the design files I have made for the Preamp board - the design is still to be verified, I will do that when I see how the controller board works out when arriving from the fabricator.

3D view from my KiCad design - I am too lazy to make my own 3D files so it is somewhat incomplete. There is a TI processor hidden on the bottom side, as is the KeyStone radio module.

If everything goes to plan I will post about the bits and pieces that makes up the complete project. I even have mechanical design files (Vectric format) that may be used to make files in order fabricate the enclosures on a CNC-machine.

Ok, enough for this time.

Terje

PreAmpBoard.zip
10. oPossum got a reaction from agaelema in Faster printing of single precision floating point
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, t; 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); ++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; }
11. oPossum got a reaction from tripwire in Precision 12 MHz clock for Launchpad MCU
The MSP430F1612 on the Launchpad provides a 12 MHz clock to the TUSB3410 chip. This clock can also be used by the MSP430 in the 20 pin socket.

Clock on pin 49 of F1612

Mask off pin 49 with Kapton tape and solder a 1k resistor to the pin.
Connect the other end of the resistor to the lower pad of C21 using a short wire.

This test program will flash the red LED five times with the DCO at ~1 MHz and then switch to the 12 MHz external clock.

#include "msp430g2231.h" void main(void) { unsigned i; volatile unsigned n = 0; WDTCTL = WDTPW | WDTHOLD; P1DIR = 0x01; P1SEL = 0x00; i = 10; do { P1OUT ^= 1; while(--n); } while(--i); BCSCTL3 = LFXT1S0 | LFXT1S1; // - Set XT1 clock type as external do { // - Wait for MSP430 to detect clock is stable IFG1 &= ~OFIFG; // Clear OFIFG n = 250; while(--n); // Wait a while } while(IFG1 & OFIFG); // Loop until OFIFG remains cleared BCSCTL2 = SELM1 | SELM0 | SELS; // - Use LFXT1CLK as clock source do { P1OUT ^= 1; while(--n); } while(1); }
12. Here's a heads-up for anyone that wants to use the external SPI flash memory on the SensorTag: it's not accessible while a debugger session is active.

Unfortunately the pin on the SensorTag's CC2650 which outputs the SPI clock to the flash memory is also used as the JTAG TDI pin:

While you're debugging using the Debug DevPack the CC2650 is unable to clock data out to the flash chip. That means the flash will just sit there doing nothing and the CC2650 will end up reading zeroes from the SPI bus.

To use the flash you need to be certain that no JTAG communication is occurring during execution of your firmware.

The easiest way to do this is just to disconnect the Debug DevPack and power the SensorTag from a coin cell or external power supply.

Alternatively you can use the Debug DevPack to power the SensorTag, but then you have to follow this procedure:
Load your updated firmware onto the SensorTag using the Debug DevPack (I just run it in the CCS debugger) Terminate the debug session once you reach the start of main() Disconnect the Debug DevPack from USB Detach the SensorTag from the DevPack Connect the Debug DevPack to USB Reattach the SensorTag to the Debug DevPack Be careful not to miss step 2, or the DevPack will resume JTAG communication when everything is connected up again. I found that out the hard way...

Also, the order of the last two steps is to avoid an issue with powering up the Debug DevPack while it's connected to a SensorTag with no coin cell. The advantage of that is that you don't need a coin cell (I've drained two already...)

This makes testing code that uses the flash really difficult, as there's no way to use the debugger. I've been using a combination of UART logging, LED flashes and beep codes from the onboard buzzer to keep track of where the code is up to.

The other thing I'm doing is detecting whether the flash is available during startup and skipping the flash accesses if it's not there. That lets the rest of the code run in the debugger without problems.

The command sequence I'm using to detect the flash is:
Repeatedly send a Read Status Register command (0x05, 0x00) until the received BUSY flag is clear Send a Read Mode Reset command (0xFF, 0xFF) Send a Release From Power Down command sequence (0xAB, 0x00, 0x00, 0x00, 0x00) Flash is available if the device ID value 0x12 is received in the last byte of the Release From Power Down sequence This sequence is arranged to work irrespective of the state of the flash chip. If JTAG is active the code will immediately fall through step 1 (BUSY flag is zero), but the received device ID at step 4 will be zero too. Step 2 covers against any remote chance that the device has ended up in dual-SPI mode. Step 3 wakes the chip if it has been put in suspend, and returns the device ID regardless.
13. oPossum got a reaction from bluehash in Code Composer Studio upgrades are now free (revised)
Edit: Upgrades to CCS are now free, not the entire product. An initial purchase is still required.

Just got this email from TI:

14. oPossum got a reaction from tripwire in Code Composer Studio upgrades are now free (revised)
Edit: Upgrades to CCS are now free, not the entire product. An initial purchase is still required.

Just got this email from TI:

15. I think it might be this. Until now, when you buy a licence you also get 1 year of subscription which entitles you to free major upgrades (5->6, 6->7 etc). Minor version updates are always free. Once the subscription runs out you needed to renew to get any major updates. It sounds like TI are dropping the subscription aspect, but the initial licence still needs to be paid for.

EDIT: Confirmed at http://www.ti.com/tool/CCSSUB:

16. I let my 5.5 subscription lapse and it looks like I would have to renew in order to get on the perpetual upgrade train.

EDIT:  Jumped the gun....found this:  http://www.ti.com/tool/ccssub  Looks like a V5 license will get you on the perpetual upgrade train.

EDIT #2: Thanks TI !!!
17. oPossum got a reaction from dubnet in Code Composer Studio upgrades are now free (revised)
Edit: Upgrades to CCS are now free, not the entire product. An initial purchase is still required.

Just got this email from TI:

18. oPossum got a reaction from tripwire in Combined PWM with interrupt not interrupting
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.
19. oPossum got a reaction from basil4j in Combined PWM with interrupt not interrupting
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.
20. oPossum reacted to Lgbeno in New MSP430 Wireless Sensor Node
I've wanted to create a batteries included, very low cost wireless sensor kit for quite a long time now.  I've made some attempts in the past but up until this point they were either too expensive to produce and too limited in expandability.  I think that I've finally struck the balance that I'm going to be pleased with.

The device is a little larger than a single AA battery, that is what it is powered off of.  It has an NCP1400 Boost converter to bump up the voltage to 3.3V.  The processor is MSP430G2553IRHB (32QFN) and it is attached to a HopeRF RF75 radio.  There are 15 GPIO available through a 0.1in female header that is sandwiched between the battery holder and the circuit board.  It plugs into a Launchpad for programming.  Footprints are available to solder on a Si7020 temp sensor, a 32kHz crystal and two LEDs.

I have the pins_energia ready and now looking at what it takes to make the @@spirilis enrf24 library work with it.  I'll also create my own library with some analog.io tie ins as well as a special surprise.

My goal is to sell these for \$9.99 after I can get them debugged.  Would anyone be interested in one?
21. oPossum got a reaction from yyrkoon in Combined PWM with interrupt not interrupting
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.
22. In addition to @@oPossum 's awesome advice, the final point that always confuses people is that each Timer has TWO different ISRs. One (TIMER0_A0_VECTOR) is a special higher priority one just for TA0CCR0, and its interrupt flag is cleared automatically by entering the ISR at all. The other one (TIMER0_A1_VECTOR) is for all of the other TA0CCRx interrupts and TAIE - this is the one that uses TAIV - its highest-priority pending flag is cleared by reading TAIV.

This code example uses both of them, so you can see: http://dev.ti.com/tirex/#/?link=MSPWare%2FDevices%2FMSP430%2FMSP430G2XX%2FMSP430G2553%2FExamples%2FC%2Fmsp430g2xx3_ta_07.c

It's a common point that trips people up.

If you currently have no ISR defined for TIMER0_A1_VECTOR but have TAIE enabled, if you use CCS for example it defines a trap ISR for all undefined ISRs for just this case (so part doesn't jump off into some random location), so your part is probably hanging out there.
23. oPossum got a reaction from KatiePier in Combined PWM with interrupt not interrupting
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.
24. oPossum reacted to Lauszus in LaunchPad Flight Controller
Hi everyone,

Just wanted to share my flight controller I wrote some time ago

Here is a video of it:

The code is available here: https://github.com/Lauszus/LaunchPadFlightController.

Regards
Kristian Sloth Lauszus
25. Stumbled across something that might be of interest to the folks on the forum that are working with CAN.  Microchip has introduced a Can Bus Analyzer that will be shipping end of September with a price of \$99.00. They have a 25% off coupon good until December of this year which brings it down to \$75.00.

CAN Bus Analyzer Tool from Microchip, part number apgdt002
Supports CAN 2.0b and ISO11898-2 Intuitive PC User Interface for functions such as configuration, trace, transmit, filter, log etc Enhanced features in the PC GUI for Microchip
×
• Blog

• #### Activity

×
• Create New...