Jump to content
43oh

timotet

Members
  • Content Count

    223
  • Joined

  • Last visited

  • Days Won

    1

Reputation Activity

  1. Like
    timotet 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
  2. Like
    timotet reacted to bluehash in Full SD-Card FatFS Elm-Chan module support for the MSP432 Launchpad   
    Many members on 43oh have requested support for a full FAT system sdcard stack using the super-awesome Elm-Chan module. This is my attempt at it. The software still needs work. so far I have tested the basics: pwd cat filename ls   Hardware: 1. The 43oh SDCard BoosterPack http://store.43oh.com/The-CardReader-SDCard-BoosterPack   2. MSP432 Launchpad https://store.ti.com/msp-exp432p401r.aspx   Software: 1. Compiled with CCS  6.1.0.00104    2. MSPWare Install http://www.ti.com/tool/MSPWARE Make sure you have msp432p4xx_driverlib.lib in the root of your project or linked for the above install folder.   The software has only been tested with a 32MB card. This is Fat16. Cards 2Gb or greater should work just as well.   Thanks to the following software: 1. ElmChan FatFS http://www.elm-chan.org/fsw/ff/00index_e.html   2. TI TivaWare for the SDCard example http://www.ti.com/tool/sw-tm4c  
    Code is on github.
     
     
  3. Like
    timotet got a reaction from bluehash in What are you doing right now..?   
    This looks awesome @@terjeio. I really like diy CNC machines and would like to see your machine.
    I've machined a couple of 2 sided pcb's and had good luck re-aligning the 2nd side.
    When I layout the pcb I put in mounting holes for a small fixture I made. Then I bolt the pcb
    to the fixture run the 1st side, pull the fixture out flip the boad and reload the fixture. It works
    pretty well.

    1st side

    2nd side through holes line up pretty well!

    finished!

    heres a shot of my robot
    thanks for posting your project, you've got me thinking about putting a laser on my printer.
  4. Like
    timotet reacted to terjeio in What are you doing right now..?   
    @@timotet - nice result from isolation milling.
     
    The first machine I made is a fairly standard CNC mill, ballscrews, linear rails & steppers, using Mach3 and Vectric Cut2D & VCarve in the toolchain. The design was inspired by Neo7CNCs machines. This is my main workhorse and vital for my projects. It is mainly used for milling aluminium parts and drilling/milling PCBs.
     

     
    The PCB printer was inspired by a youtube video "PCB Laserprinter Version 2" by "Hobby Elektronik" - he has not published any design details so I had to start from the information provided in the video.
     
    The reason for doing this was that toner transfer did not work for me, and I think isolation milling not well suited for SMD components (IMO). I could have used my main mill by adding a laser to it - but it has a fairly heavy gantry/Z-assembly so not well suited for high speed laser "printing".
     
    The "printer" is designed for PCBs up to Eurocard size (100 x 160 mm) and has a moving table mounted on a THK KR33A actuator. The laser sledge is from an old 3.5" disc drive - I thought I needed to control the focus so I choose that because the assemby contains a small stepper. This is not needed in practice - once the focus it set I have found there is no need to adjust it.
     
    I am using GT2 belt for the X-axis, combined with 17 teeth pulleys and microstepping gives it a mechanical resolution of 1196 dpi - very close to the standard 1200 dpi.
     
    The software renders bmp images directly (no conversion to G-code) so it is "pixel perfect". The PCB outline on the board above is only 5 pixels wide - a tad over 0.1mm, not bad I think. It is my first attempt at double sided printing - this was not my initial design goal so I need to add some way of achieving layer alignment. Since the table has well defined inside edges I think I can utilize that. What I will try is to mill the board slightly oversized so it aligns perfectly with the home position of the laser when I turn it. A complicating factor is that I have to accelerate the laser to max speed before I start exposing the PCB - this to ensure I do not overexpose the board on the edges.
     

     

     

  5. Like
    timotet got a reaction from terjeio in What are you doing right now..?   
    This looks awesome @@terjeio. I really like diy CNC machines and would like to see your machine.
    I've machined a couple of 2 sided pcb's and had good luck re-aligning the 2nd side.
    When I layout the pcb I put in mounting holes for a small fixture I made. Then I bolt the pcb
    to the fixture run the 1st side, pull the fixture out flip the boad and reload the fixture. It works
    pretty well.

    1st side

    2nd side through holes line up pretty well!

    finished!

    heres a shot of my robot
    thanks for posting your project, you've got me thinking about putting a laser on my printer.
  6. Like
    timotet reacted to terjeio in What are you doing right now..?   
    LQFP-64, 0.25mm tracks - PCB outline is around 0.1mm. Now, if I only can figure out a good way to align layers then prototyping double sided boards should be within reach.
     
    Since KiCAD is open source it should be possible add code to plot directly to the board - after a quick glance through the sources this seems doable...
     

     
    To build the "printer" one needs a CNC mill/router to make the parts (and drill the pcbs), so maybe it is a bit too demanding to post as a project?
     
     
  7. Like
    timotet reacted to terjeio in What are you doing right now..?   
    Making my first PCB using KiCAD, switching over from ZenitPCB. Next I am going make a prototype board with a LQFP-64 (TM4C123), will push my homemade PCB "printer" to its limits (its inherent resolution is 1200dpi).
     

     
    PCB "printer" in action - a blu-ray laser (100mW), two steppers controlled by MSP430 and main rendering program written i C# for Windows.
     

     

     
    First PCB authored in KiCad - laminator is no good, and I am having some problems with dust. I am using Riston film - maybe better to use presensitized boards...
     
     
     
  8. Like
    timotet reacted to David Bender in Interface push button rotary encoder on 1 analog input   
    I had a lack of digital input pins for a pushbutton rotary encoder switch so I used an analog input.
      I wrote up my results here: https://analog10.com/posts/rotary_encoder_analog_input.html
      It works pretty well except for an occasional reverse tick but that's probably a flaw in my code.
     
  9. Like
    timotet reacted to greeeg in RGB 4x4 button thing   
    It's been awhile since I've done a proper project, mainly been doing alot of tinkering.
     
    But I have a new project that I'd like to share. I wanted to make something like sparkfuns 2x2 Simon game. but using adafruits 4x4 silicone buttons.
    Ofcourse adafruit sell a breakout board with an i2c keypad scanner/single colour led driver.
     
    I thought how hard is it to replicate that design, but add SMD RGB LEDs under each button!! Now this is still a work in progress.
    Here is the schematic, there isn't too much to the design. Just a MSP430F55xx 64QFN and a TLC5955 48 channel 16bit LED driver.
    Because I'm using such a large MSP, I trashed a keypad multiplexing idea and went straight for direct. the same with the LEDs.

     
    The board isn't very fancy either. This was my first board with kicad, moved from altium. (I needed to make the change sometime, will not be able to afford a non-student license)

     
    I haven't doe any software for this project. and this is the first USB project I've ever made. So progress might be slow. but I'm interested if you guys have ideas for this platform.
     
    I'm not sure if the stock USB bootloader can be called from software? I know that the ezFET does this, but they use custom BSL code, which I might need to look into.
    I have a fair bit of leftovers and might consider placing some boards on tindie, the only downside is that the two ICs are expensive and practically double the BOM.
     
    ----Edit----
    TLC5955, not TLC5595
  10. Like
    timotet reacted to oPossum in Printing large numbers in small spaces (64 bits in 5 chars)   
    This code will print a 64 bit unsigned integer in 5 characters using 3 significant digits and and an SI prefix. Several revisions are shown beginning with the obvious implementation and then optimizing it to improve speed and decrease code size. Compilers used are TI 4.4.4 and GCC 4.9.1 Test hardware is the F5529 Launchpad running at the default clock of 1.016 MHz.
     
    The general strategy of the code is:
    - Count the number of digits in the decimal representation
    - Divide the value to reduce it to 3 digits.
    - Print the 3 digits with proper formatting and SI prefix.
    - Handle the special case of values of 99 or less that must be printed with 2 or 1 digits and no decimal.
     
    A series of values from zero to the maximum possible 64 bit value are used to test the performance and correct operation of the code...

    static const uint64_t td[] = { 0ULL, 1ULL, 12ULL, 123ULL, 1234ULL, 12345ULL, 123456ULL, 1234567ULL, 12345678ULL, 123456789ULL, 1234567890ULL, 12345678901ULL, 123456789012ULL, 1234567890123ULL, 12345678901234ULL, 123456789012345ULL, 1234567890123456ULL, 12345678901234567ULL, 123456789012345678ULL, 1234567890123456789ULL, 12345678901234567890ULL, 18446744073709551615ULL }; The first version uses C standard library functions for a very simple implementation. Decimal digits are counted using log10(). Dividing the digit count by three using the div() function provides values for formatting, division, and the SI prefix. The divisor needed to reduce the value to three digits is calculated with pow(). The special case of values of 99 or less is handled by using a fixed digit count for values less than 1000 rather than the actual base ten digit count. Conversion from uint64_t to double will have a loss of precision for large values due to float having a 52 bit significand. This is not a problem for this code because only three significant digits are printed.Code size for the TI compiler is 20,636 bytes and the execution time for the test case is 1.22 seconds. The GCC compiler does not produce working code.

    static void sprint_f3d(char * s, double f) { static char const * const fmt[3] = { "%1.2f%c", "%2.1f%c", "%4.0f%c" }; div_t const d = div((f < 1000.0) ? 2 : (int)log10(f), 3); sprintf(s, fmt[d.rem], f / pow(1000.0, d.quot), " kMGTPEZY"[d.quot]); } The C standard library does not have integer versions of log10() and pow(), so another strategy will be used. The value is divided by 10 until it is less than 1000. The number of divisions is counted to determine the number of base ten digits. Stopping the division when the value is less than 1000 handles the special case for values of 99 or less by limiting the digit count to 3 or more. The resulting 3 digit value will be split as necessary for formatting using the div() library function.Code size for the TI compiler is 5,346 bytes and the execution time for the test case is 3.24 seconds.
    Code size for the GCC compiler is 36,040 bytes and the execution time for the test case is 981 milliseconds.
    The poor performance of the TI compiler is due the an inefficient intrinsic 64 bit unsigned divide.

    static void sprint_u64_a(char *s, uint64_t n) { unsigned d = 2; while(n >= 1000) n /= 10, ++d; div_t qr = div(d, 3); char const u = " kMGTPE"[qr.quot]; switch(qr.rem) { case 0: qr = div((int)n, 100); sprintf(s, "%i.%02i%c", qr.quot, qr.rem, u); break; case 1: qr = div((int)n, 10); sprintf(s, "%2i.%i%c", qr.quot, qr.rem, u); break; case 2: sprintf(s, "%4i%c", (int)n, u); break; } } Using this 64 bit unsigned divide provides much better performance on the TI compiler, but much worse on the GCC compiler.Code size for the TI compiler is 5,666 bytes and the execution time for the test case is 396 milliseconds.
    Code size for the GCC compiler is 36,116 bytes and the execution time for the test case is 4.06 seconds.
    Future revisions will use intrinsic divide for GCC and this divide function for TI.

    static uint64_t divu64(uint64_t n, uint64_t d) { if((n < d) || (!d)) return 0; uint64_t register b = 1; if(((uint16_t)(n >> 48)) & 0x8000) { while(!(((uint16_t)(d >> 48)) & 0x8000)) d <<= 1, b <<= 1; if(n < d) d >>= 1, b >>= 1; } else { d <<= 1; while(n >= d) d <<= 1, b <<= 1; d >>= 1; } uint64_t q = b; n -= d; while(!(b & 1)) { d >>= 1; b >>= 1; if(n >= d) n -= d, q |= b; } return q; } The number of 64 bit divides can be reduced by using constants of 10 to the power of 2 to the power of N rather than iterative division by 10.Code size for the TI compiler is 5,886 bytes and the execution time for the test case is 160 milliseconds.
    Code size for the GCC compiler is 36,256 bytes and the execution time for the test case is 223 milliseconds.

    unsigned d = 2; if(n >= 1000000000000000000ULL) n = divu64(n, 10000000000000000ULL), d += 16; if(n >= 10000000000ULL) n = divu64(n, 100000000ULL), d += 8; if(n >= 1000000ULL) n = divu64(n, 10000ULL), d += 4; if(n >= 10000ULL) n = divu64(n, 100ULL), d += 2; if(n >= 1000ULL) n = divu64(n, 10ULL), ++d; The number of 64 bit divides can be reduced to one by using a table to determine the number of base ten digits. The table is searched for the highest value that is less than or equal to the value to be printed. The value is then divided by the table entry that is 1/100th of the value representing the base ten digit count to reduce the value to 3 digits.Code size for the TI compiler is 5,886 bytes and the execution time for the test case is 143 milliseconds.
    Code size for the GCC compiler is 36,096 bytes and the execution time for the test case is 143 milliseconds.

    static uint64_t const pt[] = { // Powers of 10 // 18446744073709551615 // 2^64 - 1 10000000000000000000ULL, // 10^19 NN.N E 1000000000000000000ULL, // 10^18 N.NN E 100000000000000000ULL, // 10^17 NNN P 10000000000000000ULL, // 10^16 NN.N P 1000000000000000ULL, // 10^15 N.NN P 100000000000000ULL, // 10^14 NNN T 10000000000000ULL, // 10^13 NN.N T 1000000000000ULL, // 10^12 N.NN T 100000000000ULL, // 10^11 NNN G 10000000000ULL, // 10^10 NN.N G // 4294967295 // 2^32 - 1 1000000000ULL, // 10^9 N.NN G 100000000ULL, // 10^8 NNN M 10000000ULL, // 10^7 NN.N M 1000000ULL, // 10^6 N.NN M 100000ULL, // 10^5 NNN k 10000ULL, // 10^4 NN.N k 1000ULL, // 10^3 N.NN k 100ULL, // 10^2 NNN 10ULL, // 10^1 NN 1ULL, // 10^0 N }; unsigned d = 2; if(n >= 1000) { d = 19; uint64_t const *p = pt; while (n < *p) ++p, --d; n = divu64(n, p[2]); } The sprintf() function takes significant space, so it is replaced with decimal to ASCII conversion using the div() library function.Code size for the TI compiler is 1,660 bytes and the execution time for the test case is 25.8 milliseconds.
    Code size for the GCC compiler is 3,384 bytes and the execution time for the test case is 82.0 milliseconds.

    div_t qr; qr.rem = (int)n; div_t const dp = div(d, 3); if(dp.rem == 2) *s++ = ' '; if(qr.rem < 100) { *s++ = ' '; qr.quot = 0; } else { qr = div(qr.rem, 100); *s++ = '0' + qr.quot; } if(dp.rem == 0) *s++ = '.'; if((!qr.quot) && (qr.rem < 10)) { *s++ = ' '; } else { qr = div(qr.rem, 10); *s++ = '0' + qr.quot; } if(dp.rem == 1) *s++ = '.'; *s++ = '0' + qr.rem; *s++ = " kMGTPE"[dp.quot]; *s = 0; The final optimization removes all division. The base ten tables values are used with iterative subtraction to create the ASCII string.Code size for the TI compiler is 1,368 bytes and the execution time for the test case is 10.8 milliseconds.
    Code size for the GCC compiler is 2,452 bytes and the execution time for the test case is 19.9 milliseconds.

    uint64_t const *p = pt + 17; if(n >= 1000) { p = pt; while (n < *p) ++p; } // n += (p[2] >> 1); // optional rounding int dp = p - pt; while (dp > 2) dp -= 3; if (dp == 2) *s++ = ' '; char c; if(n < 100) { c = ' '; } else { c = '0'; while(n >= *p) n -= *p, ++c; } *s = c; ++p; if(dp == 1) *++s = '.'; if((*s == ' ') && (n < 10)) { c = ' '; } else { c = '0'; while(n >= *p) n -= *p, ++c; } *++s = c; ++p; if(dp == 0) *++s = '.'; c = '0'; while (n >= *p) n -= *p, ++c; *++s = c; *++s = " EEPPPTTTGGGMMMkkk "[p - pt]; *++s = 0; Performance summary
    function TI GCC ---------------------------------------------- sprint_u64 1368 10.8 ms 2452 19.9 ms sprint_u64_e 1660 25.8 ms 3384 82.0 ms sprint_u64_d 5886 143 ms 36096 143 ms sprint_u64_c 5886 160 ms 36256 223 ms sprint_u64_b 5666 396 ms 36116 4.06 s sprint_u64_a 5346 3.24 s 36040 981 ms sprint_f3d 20636 1.22 s non-functional Network bandwidth display (lower right) using 3 digits.
     
    Complete code

    #include <msp430.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <stdio.h> #define PU64 sprint_u64 //#define PU64 sprint_u64_e //#define PU64 sprint_u64_d //#define PU64 sprint_u64_c //#define PU64 sprint_u64_b //#define USE_DIV_FUNC //#define PU64 sprint_u64_a //#define PU64 sprint_f3d //#define PU64 sprint_u64_null static void sprint_u64(char *s, uint64_t n) { static uint64_t const pt[] = { // Powers of 10 // 18446744073709551615 // 2^64 - 1 10000000000000000000ULL, // 10^19 NN.N E 1000000000000000000ULL, // 10^18 N.NN E 100000000000000000ULL, // 10^17 NNN P 10000000000000000ULL, // 10^16 NN.N P 1000000000000000ULL, // 10^15 N.NN P 100000000000000ULL, // 10^14 NNN T 10000000000000ULL, // 10^13 NN.N T 1000000000000ULL, // 10^12 N.NN T 100000000000ULL, // 10^11 NNN G 10000000000ULL, // 10^10 NN.N G // 4294967295 // 2^32 - 1 1000000000ULL, // 10^9 N.NN G 100000000ULL, // 10^8 NNN M 10000000ULL, // 10^7 NN.N M 1000000ULL, // 10^6 N.NN M 100000ULL, // 10^5 NNN k 10000ULL, // 10^4 NN.N k 1000ULL, // 10^3 N.NN k 100ULL, // 10^2 NNN 10ULL, // 10^1 NN 1ULL, // 10^0 N }; uint64_t const *p = pt + 17; if(n >= 1000) { p = pt; while (n < *p) ++p; } // n += (p[2] >> 1); // optional rounding int dp = p - pt; while (dp > 2) dp -= 3; if (dp == 2) *s++ = ' '; char c; if(n < 100) { c = ' '; } else { c = '0'; while(n >= *p) n -= *p, ++c; } *s = c; ++p; if(dp == 1) *++s = '.'; if((*s == ' ') && (n < 10)) { c = ' '; } else { c = '0'; while(n >= *p) n -= *p, ++c; } *++s = c; ++p; if(dp == 0) *++s = '.'; c = '0'; while (n >= *p) n -= *p, ++c; *++s = c; *++s = " EEPPPTTTGGGMMMkkk "[p - pt]; *++s = 0; } static uint64_t divu64(uint64_t n, uint64_t d) { #if defined( __GNUC__) & !defined(USE_DIV_FUNC) return n / d; #else if((n < d) || (!d)) return 0; uint64_t register b = 1; if(((uint16_t)(n >> 48)) & 0x8000) { while(!(((uint16_t)(d >> 48)) & 0x8000)) d <<= 1, b <<= 1; if(n < d) d >>= 1, b >>= 1; } else { d <<= 1; while(n >= d) d <<= 1, b <<= 1; d >>= 1; } uint64_t q = b; n -= d; while(!(b & 1)) { d >>= 1; b >>= 1; if(n >= d) n -= d, q |= b; } return q; #endif } static void sprint_u64_e(char *s, uint64_t n) { static uint64_t const pt[] = { // Powers of 10 // 18446744073709551615 // 2^64 - 1 10000000000000000000ULL, // 10^19 NN.N E 1000000000000000000ULL, // 10^18 N.NN E 100000000000000000ULL, // 10^17 NNN P 10000000000000000ULL, // 10^16 NN.N P 1000000000000000ULL, // 10^15 N.NN P 100000000000000ULL, // 10^14 NNN T 10000000000000ULL, // 10^13 NN.N T 1000000000000ULL, // 10^12 N.NN T 100000000000ULL, // 10^11 NNN G 10000000000ULL, // 10^10 NN.N G // 4294967295 // 2^32 - 1 1000000000ULL, // 10^9 N.NN G 100000000ULL, // 10^8 NNN M 10000000ULL, // 10^7 NN.N M 1000000ULL, // 10^6 N.NN M 100000ULL, // 10^5 NNN k 10000ULL, // 10^4 NN.N k 1000ULL, // 10^3 N.NN k 100ULL, // 10^2 NNN 10ULL, // 10^1 NN 1ULL, // 10^0 N }; unsigned d = 2; if(n >= 1000) { d = 19; uint64_t const *p = pt; while (n < *p) ++p, --d; n = divu64(n, p[2]); } div_t qr; qr.rem = (int)n; div_t const dp = div(d, 3); if(dp.rem == 2) *s++ = ' '; if(qr.rem < 100) { *s++ = ' '; qr.quot = 0; } else { qr = div(qr.rem, 100); *s++ = '0' + qr.quot; } if(dp.rem == 0) *s++ = '.'; if((!qr.quot) && (qr.rem < 10)) { *s++ = ' '; } else { qr = div(qr.rem, 10); *s++ = '0' + qr.quot; } if(dp.rem == 1) *s++ = '.'; *s++ = '0' + qr.rem; *s++ = " kMGTPE"[dp.quot]; *s = 0; } static void sprint_u64_d(char *s, uint64_t n) { static uint64_t const pt[] = { // Powers of 10 // 18446744073709551615 // 2^64 - 1 10000000000000000000ULL, // 10^19 NN.N E 1000000000000000000ULL, // 10^18 N.NN E 100000000000000000ULL, // 10^17 NNN P 10000000000000000ULL, // 10^16 NN.N P 1000000000000000ULL, // 10^15 N.NN P 100000000000000ULL, // 10^14 NNN T 10000000000000ULL, // 10^13 NN.N T 1000000000000ULL, // 10^12 N.NN T 100000000000ULL, // 10^11 NNN G 10000000000ULL, // 10^10 NN.N G // 4294967295 // 2^32 - 1 1000000000ULL, // 10^9 N.NN G 100000000ULL, // 10^8 NNN M 10000000ULL, // 10^7 NN.N M 1000000ULL, // 10^6 N.NN M 100000ULL, // 10^5 NNN k 10000ULL, // 10^4 NN.N k 1000ULL, // 10^3 N.NN k 100ULL, // 10^2 NNN 10ULL, // 10^1 NN 1ULL, // 10^0 N }; unsigned d = 2; if(n >= 1000) { d = 19; uint64_t const *p = pt; while (n < *p) ++p, --d; n = divu64(n, p[2]); } div_t qr = div(d, 3); char const u = " kMGTPE"[qr.quot]; switch(qr.rem) { case 0: qr = div((int)n, 100); sprintf(s, "%i.%02i%c", qr.quot, qr.rem, u); break; case 1: qr = div((int)n, 10); sprintf(s, "%2i.%i%c", qr.quot, qr.rem, u); break; case 2: sprintf(s, "%4i%c", (int)n, u); break; } } static void sprint_u64_c(char *s, uint64_t n) { unsigned d = 2; if(n >= 1000000000000000000ULL) n = divu64(n, 10000000000000000ULL), d += 16; if(n >= 10000000000ULL) n = divu64(n, 100000000ULL), d += 8; if(n >= 1000000ULL) n = divu64(n, 10000ULL), d += 4; if(n >= 10000ULL) n = divu64(n, 100ULL), d += 2; if(n >= 1000ULL) n = divu64(n, 10ULL), ++d; div_t qr = div(d, 3); char const u = " kMGTPE"[qr.quot]; switch(qr.rem) { case 0: qr = div((int)n, 100); sprintf(s, "%i.%02i%c", qr.quot, qr.rem, u); break; case 1: qr = div((int)n, 10); sprintf(s, "%2i.%i%c", qr.quot, qr.rem, u); break; case 2: sprintf(s, "%4i%c", (int)n, u); break; } } static void sprint_u64_b(char *s, uint64_t n) { unsigned d = 2; while(n >= 1000) n = divu64(n, 10), ++d; div_t qr = div(d, 3); char const u = " kMGTPE"[qr.quot]; switch(qr.rem) { case 0: qr = div((int)n, 100); sprintf(s, "%i.%02i%c", qr.quot, qr.rem, u); break; case 1: qr = div((int)n, 10); sprintf(s, "%2i.%i%c", qr.quot, qr.rem, u); break; case 2: sprintf(s, "%4i%c", (int)n, u); break; } } static void sprint_u64_a(char *s, uint64_t n) { unsigned d = 2; while(n >= 1000) n /= 10, ++d; div_t qr = div(d, 3); char const u = " kMGTPE"[qr.quot]; switch(qr.rem) { case 0: qr = div((int)n, 100); sprintf(s, "%i.%02i%c", qr.quot, qr.rem, u); break; case 1: qr = div((int)n, 10); sprintf(s, "%2i.%i%c", qr.quot, qr.rem, u); break; case 2: sprintf(s, "%4i%c", (int)n, u); break; } } static void sprint_f3d(char * s, double f) { static char const * const fmt[3] = { "%1.2f%c", "%2.1f%c", "%4.0f%c" }; div_t const d = div((f < 1000.0) ? 2 : (int)log10(f), 3); sprintf(s, fmt[d.rem], f / pow(1000.0, d.quot), " kMGTPEZY"[d.quot]); } static void sprint_u64_null(char *s, uint64_t n) { *s = 0; } static void print(char const *s) { while(*s) { while(!(UCA1IFG & UCTXIFG)); UCA1TXBUF = *s++; } } #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 static const uint64_t td[] = { 0ULL, 1ULL, 12ULL, 123ULL, 1234ULL, 12345ULL, 123456ULL, 1234567ULL, 12345678ULL, 123456789ULL, 1234567890ULL, 12345678901ULL, 123456789012ULL, 1234567890123ULL, 12345678901234ULL, 123456789012345ULL, 1234567890123456ULL, 12345678901234567ULL, 123456789012345678ULL, 1234567890123456789ULL, 12345678901234567890ULL, 18446744073709551615ULL }; char s[32]; int n; uint64_t const *p; // Print test array to application UART print("\r\n"); n = sizeof(td) / sizeof(td[0]); p = td; do { PU64(s, *p++); print(s); print("\r\n"); } while(--n); // Time the test array - make string only - do not print TA0EX0 = 7; TA0CTL = TASSEL_2 | ID_3 | MC_2; TA0CTL |= TACLR; n = sizeof(td) / sizeof(td[0]); p = td; do { PU64(s, *p++); } while(--n); uint64_t et = TA0R * 63ULL; // Elapsed time in microseconds PU64(s, et); print(s); print(" us\r\n"); for(;; return 0; }
  11. Like
    timotet got a reaction from GastonP in MSP430 Nixie Clock   
    I bought one of @@RobG's clock kits and I am very happy with the results.
    I have kids and didn't want to have any wandering fingers getting zapped, so I designed and printed an enclosure for it.
    Here are some photos of it. I couldn't resist adding the colon.
     
    I uploaded the .stl files if anyone wants to print it.
     
    Thanks to Rob for the awesome kit!
     



    RobG_Clock_Case.zip
  12. Like
    timotet got a reaction from bluehash in LCD TFT Boosterpack   
    Hi @@pallisi,
     
    It sounds like the pin assignments are wrong, Its pretty easy to check though, only 4 pins.
    From the picture on RobG's tindie page it looks like the 4 configurable jumpers are:
    JP1 for the display chip select, you want to jumper that to gpio19 (J2_2) on your c2000 launchpad.
    JP2 for for the D/C select, you want to jumper that to gpio12 (J2_3) on your c2000 launchpad.
    JP3 is for the backlight, It looks like that could go to either J1_8, or J1_10 on the c2000 launchpad.
    Both of which are ADC inputs , but they can be configured as gpio. Thats not in the code I sent you though.
    You may want to jumper it to 3.3v for now. The booster pack I have seems to have the backlight hardwired.
    JP4 is for the SD card chip select, thats for later.
     
    I know the C2000 LP is setup by default to use the BP standard for spi, same as the msp430 and other LPs use that being
    MISO on pin J2_6, MOSI on J2_7, SCLK on J1_7.
     
    When I used the Booster pack on the C2000 I remember having to jumper the CS an DC lines.
     
    Good luck
    Tim
  13. Like
    timotet reacted to pallisi in LCD TFT Boosterpack   
    @timotet 
     
    Thank you very much. I managed to make it work by reassigning the pins from the code. I was using wrong schematics that's why I couldn't find the solution. I will soon post the code in order to share it with the community.
  14. Like
    timotet got a reaction from jpnorair in I want to buy an awesome 3D Printer   
    This looks pretty neat too. Not much Z travel though.
     
    https://www.inventables.com/technologies/carvey
  15. Like
    timotet 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.
     
    You can read more about it at my blog: http://blog.tkjelectronics.dk/2015/01/launchpad-flight-controller/.
     

     
    Regards
    Kristian Sloth Lauszus
  16. Like
    timotet got a reaction from bluehash in Updates and going forward   
    I have to chime in and say I like the idea of one forum, with sub forums for the different chips. Seems easier to manage.
    It's too bad about the c2000 forum going away but nobody goes there and the chip has a steep learning curve.
    With a sub forum aleast that info would not go away completley .
    I agree with @@Fred on energia having a forum all its own, not because I think its not a good thing, but it may be
    easier for the people who use it to find the content there.
  17. Like
    timotet reacted to zeke in General use triac boards   
    @@swampdonkeykami, I sense your frustration. Please be patient.
     
    I suggest venting your emotions elsewhere then coming back with constructive questions using kinder words.
  18. Like
    timotet got a reaction from bluehash in MSP430 Nixie Clock   
    I bought one of @@RobG's clock kits and I am very happy with the results.
    I have kids and didn't want to have any wandering fingers getting zapped, so I designed and printed an enclosure for it.
    Here are some photos of it. I couldn't resist adding the colon.
     
    I uploaded the .stl files if anyone wants to print it.
     
    Thanks to Rob for the awesome kit!
     



    RobG_Clock_Case.zip
  19. Like
    timotet got a reaction from tripwire in MSP430 Nixie Clock   
    I bought one of @@RobG's clock kits and I am very happy with the results.
    I have kids and didn't want to have any wandering fingers getting zapped, so I designed and printed an enclosure for it.
    Here are some photos of it. I couldn't resist adding the colon.
     
    I uploaded the .stl files if anyone wants to print it.
     
    Thanks to Rob for the awesome kit!
     



    RobG_Clock_Case.zip
  20. Like
    timotet got a reaction from roadrunner84 in MSP430 Nixie Clock   
    I bought one of @@RobG's clock kits and I am very happy with the results.
    I have kids and didn't want to have any wandering fingers getting zapped, so I designed and printed an enclosure for it.
    Here are some photos of it. I couldn't resist adding the colon.
     
    I uploaded the .stl files if anyone wants to print it.
     
    Thanks to Rob for the awesome kit!
     



    RobG_Clock_Case.zip
  21. Like
    timotet got a reaction from RobG in MSP430 Nixie Clock   
    I bought one of @@RobG's clock kits and I am very happy with the results.
    I have kids and didn't want to have any wandering fingers getting zapped, so I designed and printed an enclosure for it.
    Here are some photos of it. I couldn't resist adding the colon.
     
    I uploaded the .stl files if anyone wants to print it.
     
    Thanks to Rob for the awesome kit!
     



    RobG_Clock_Case.zip
  22. Like
    timotet reacted to pabigot in New BSP430 release available   
    BSP430 has been updated to the 20141115 release, which includes full support for msp430-elf and support for the new FR4xx/2xx chip families. Details are available on the web site.
     
    Of particular interest to 43oh folks might be the updated script to build an msp430-elf toolchain, and the newlib sys integration.
     
    If you use BSP430 and encounter any problems, please file issue reports on github.
     
    This is the last version of BSP430 that will default to mspgcc. Henceforth it's going to be msp430-elf, though mspgcc will still be supported (at about the level that CCS is supported, i.e. not very much). I highly recommend everybody else start transitioning too. The new toolchain has its problems, but it's still the way forward.
  23. Like
    timotet reacted to pabigot in Exercise: Robust Digital Edge Detection   
    Alright, the problem's been identified and we're now down in the weeds. Rather than point out issues in solutions-in-progress, below is my explanation of the flaw and how I'm solving it. Please point out anything that seems wrong or doesn't satisfy the requirements as stated. Those who want to keep trying should not read this post yet.
     
    The key phrase, as is so often the case, is: "race condition"
     
    The MSP430 features that impact it are (1) the PxIFG register records only edge transitions, not signal level, and (2) disabling interrupts only delays notification of a detected event, it does not delay recording the event.
     
    What's wrong here is: At any point after (1) the pin state may change. If it changes an odd number of times before (3), we'll be configured to detect the wrong edge, and the state will always be opposite the real value.
     
    This has two problems.
     
    First, if the transition occurred during a long period with interrupts disabled, the state may have changed back prior to the interrupt handler being invoked, so again we get out of sync. One might argue that such a change should be characterized as "transient" even if it exceeded the arbitrary 20-cycle limit. From the perspective that leaving interrupts disabled that long is poor design I'd probably concede the point, so this quibble is weak.
     
    But second, as with configure the state may change between (1) and (4), again desynchronizing the state and the edge being detected.
     
    The following approach solves both problems. First, we need to be absolutely sure that the edge we're looking for will detect a change from the state we think we're in. Use the following function:
     

    static __inline__ void configure_state_detection () { do { state = PxIN & BITn; // 1 : record state if (state) { PxIES |= BITn; // 2a : High, detect falling edge } else { PxIES &= ~BITn; // 2b : Low, detect rising edge } PxIFG &= ~BITn; // 3 : Reset interrupts from past changes } while ((PxIN & BITn) != state); // 4 : loop if state changed } This is much like the original naive configuration, but skips the PxIE setting and makes sure that the state after configuring the edge matches the state for which the edge was configured. So we know we're looking for the right edge, even if it changed while we were setting things up. 
    Then use that in these contexts:
     
    Configure:

    __disable_interrupt(); configure_state_detection(); // 1 : safe set state and edge detection PxIE |= BITn; // 2 : Enable interrupts on state change, may fire right away __enable_interrupt(); Nothing special for configure. Monitor changes a lot: 
    Monitor:

    int in_state = state; configure_state_detection(); // 1 : safe set state and edge detection if (in_state != state) { if (state) { // 2a : emit rising edge event } else { // 2b : emit falling edge event } } This makes sure that state has actually changed within the resolution of our ability to detect it. (As with the rejected quibble above, we'll assume that any even number of changes between the original edge and the execution of the handler are ignorable within the bounds of "transient". If they had to be reported, interrupts were disabled too long and there is no viable solution.) 
    Eagle-eyed folks will notice that there is a race condition in configure_state_detection: If the state changes a positive even number of times between (3) and (4) we're going to get a spurious interrupt as soon as Configure re-enables interrupts. However, this doesn't matter because the Monitor implementation will detect that no effective change occurred and will not generate an event.
     
    Because this safely resynchronizes the state and the PxIES configurations each time the state is inspected, and we only generate events when the state actually changed, it's also safe against the subtlety that setting PxIES can produce spurious interrupts.
     
    Addendum 2014-09-29T11:50: I should make clear that the state variable must be marked volatile as it's a global that is mutated within an ISR and read outside the ISR. Technically some hyper-optimizing compiler might otherwise allow the application to process an event while looking at an out-of-date value of state.
  24. Like
    timotet reacted to RobG in MSP430 Nixie Clock   
    MSP430 based Nixie tube clock.
     

     
    I was looking for some nice Nixie tube digit images so I could add them to my EduKit library, but I couldn't find any usable ones. I decided to just buy few of them and photograph myself. Then I thought that it would be a horrible waste if they just sit in a drawer. So here it is, my first Nixie project since... 1987.
     
    This clock will be available as kit, but since this is v1, I will most likely make some adjustments.
    Any suggestions are welcome.
     

  25. Like
    timotet reacted to pabigot in Scan Interface Applications - Five Members Win A Target Board And An MSP-FET   
    There are still plenty of infelicities, if not bugs, but for the record I intend to use msp430-elf for all my own future development.  I do, however, build my own from upstream gcc to which RedHat doesn't always promptly push their updates (e.g. the large memory support in the current TI release hasn't been upstreamed yet).
     
    I also have a local git archive that tracks all the TI public releases (source and headers), which I'll put on github next time I'm working MSP430.  Makes it easier to figure out what changed with each release (and what's not yet pushed upstream).
×
×
  • Create New...