Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Posts posted by greeeg

  1. @Peabody The MSP430F5514 does have a default USB based BSL. (It's located in FLASH and can be user modified)

    I wanted to create a firmware upgrade process that anyone could perform. Copying a single firmware.bin is easier for a non tech savy to grasp. 

    Additionally to enter the integrated BSL extra hardware changes are required. the PUR pin must be held high while the RST pin is toggled. This has an advantage that even a bad firmware cannot brick the bootloader. I would have liked to add some additional circuitry to enable this feature. (Hold down button for ~15 seconds to enter bootloader mode).

    Because my hardware lacks an extra button I opted to roll my own. I'd say it works pretty well.

  2. Finally got around to coding a bootloader for this project.

    I'm posting version 0.1 here for reference. Lots of times people seem to have trouble with bootloaders (I put off writing one for ages) But this should show you can start simple, and optimise later.

    The code right now is very rough. But is written in a way that could allow updating of itself it the help of a bootstrap Application. ie: Load new application which when run loads a new bootloader. This bootloader isn't 100% fool proof, if a bad app is loaded that fails to perform as a USB MSC then the user cannot use the USB port to load a new firmware file. but the SD can always be removed and a file copied from a PC if required. Worst case a debugger is required (Which is how they run right now)

    Memory Map

    Here is the memory map I've adopted. The bootloader fits at the top of FLASH, the default reset vector always runs the bootloader. 



    The bootloader uses petiet FatFS to read "firmware.bin" off an SD card. It checks the file integrity with a CRC16 integrated into the firmware.bin file on a PC after it was compiled (last word of file). If the file is valid it check the current apps CRC, if they match then app runs. (Application already loaded). If they do not match the Application flash is erased and the new app loaded.


    Running the Application

    When launching the app it's CRC is checked to ensure it has loaded correctly. (This shouldn't happen, but you never know...) The App's Interrupt vectors are copied to top of RAM, and SYSCTL.SYSRIVECT is set. The address at the apps reset vector (0xDFFC) is called.


    Application changes

    Due to the construction of this bootloader the app needs to have a few changes made, specifically to the linker script. 

    • Reduce FLASH boundaries to remove bootloader area
    • Shift Interrupt Vectors to alternate location in flash. (the app doesn't need to know its vectors will be moved to RAM, they just need to be in a fixed location so the bootloader can do that)
    • Remove top 128 bytes of RAM (This is where the new interrupt vectors go. but default this is where the stack is initialised. which will damage the interrupt vectors)
    • Create .crc section (Ensure a fixed WORD is placed to hold our CRC value.)


    I set up a build setting to output a Binary file format which I run through a simple C program to compute and fill the CRC value. These are all run automatically when the app is built.


    • Reduce code size (I have a feeling an SD bootloader could squeeze under 4kb, right now it's at ~6kb)
    • Improve speed, I'm not using the DMA, which could be used to improve speed (Update takes ~10s)
    • Utilise High memory (Right now I'm not enabling the use of high memory, the MSP430F5514 has 17kb in >0x10000 address range.)
      • High memory could be utilised to hold the bootloader this would free up (~7.5kb ) that the Main app could use.


  3. This project was put on hold over the holidays. It's always a busy time, plus the club doesn't hold meets over summer.

    But I have just completed another 10 units. More of the same, but thought you guys might enjoy some more photos.







    I couldn't get the same batteries as the last batch, which were 650mAh, these have much smaller 220mAh. But this still provides about 4 hours of run time.

    The uBlox GPS modules are a huge improvement. Even without the SAW filter in the RF path and the sub-optimal PCB size compared to the antenna. These find more GPS satellites faster than the G.top modules, plus they also use glonass which doubles the visible satellites.



  4. Companies like Saleae, and Segger are notorious for charging for too much money for their products.


    I would say that for a typical application the cost COULD pay itself off VERY quickly with time saved debugging. Of course it does depend on what you do. Often hobbyist/small commercial projects that's not so true.


    I personally have a OpenBench Logic Sniffer. (Which is compatible with Sigrok) I've really only used it a handful of times, The best example from my use case was reverse engineering an old B/W LCD module that I wanted to use in my project. But typically I'm much more productive with a Scope. (But of course limited to 4 channels.)

  5. It's a modified aquarium pump with an improvised foot pedal (piece of wood with a hole to cover with your toe to enable the suction action). The airflow is not sufficient for larger parts, but 0603 works great. I got it off eBay two years ago for $20 or so.


    You should try some larger needle tips. My pickup tool is a small DC motor pump + PVC tubing and Luer-loc syringes, I've found switching to larger diameter tip enables me to pickup larger parts TSSOP and 32 pin TQFP.

  6. By the way, that spindle has an option for water cooling, and i you noticed the lexan "tub" around the table. It's also meant to mill while the part is submerged in water. If the user so wishes.


    For typical 3d milling I've had great success with Fusion 360 (free for hobbyists and small <$100K/yr startups) (windows only) for creating G-code. You'll then need to feed that G-code into Mach-3 to actually run your machine.


    I doubt having the part submerged in water is a good idea. (also tub doesn't look big enough) From my understanding coolant's main purpose it to extract heat as-well as remove chips from the cutting area. A submersed part will not aid with the chip evacuation.


    Lastly I believe that the spindle will require water cooling, but that is a completely separate cooling loop from the part coolant. This is purely to cool the spindle motor itself.

  7. ...

    Funnily though, I received a total of 4 separate packages for all the stuff



    It's weird that they do that, given that I believe it all comes from digikey's warehouse.




    I just got a new (to me) air filter (a purex fumecube 2). and I bought a Hakko Fume extractor nozzle to pair with it.

    Hakko obviously wasn't designed for the Purex and didn't fit....so I had an excuse to 3d print an adapter + cap.


    Already love it, it's great being able to look right over your work and not have to worry about flux smoke. The Hakko arm moves around easily but stays pretty rigid as you can see.

    I'm sure future me will be grateful in avoiding smoke damage to my lungs.

  8. I have used sample programs in the past as a Hobbyist back in high school. I don't believe that it was strictly against their T&C back then. But given the growth of electronics over the past 5 years I can see a samples program getting out of hand. Pretty sure all the big companies require .com corporate emails.


    Personally I don't understand samples. Surely the couple of dollars worth of chips is almost a drip compared to the NRE costs of a typical commercial project?

  9. @@yyrkoon


    • Double sided alignment - I believe that you can use some form of holes and pins to re-align the PCB. This may have gotten better, but I never had a good workflow. Your CNC probably needs a nice fixture plate to make this reliable.
    • Plated Through holes - Fair, enough. (This is a show stopper for me)
    • Small SMT parts - I haven't seen a milled PCB that went below 0.65mm pitch TTSOPs. You should be fine for SMT passives.
    • Commercial solutions - I was talking about a commercial PCB prototype plotter. My only experience was with this (http://www.lpkf.com/products/rapid-pcb-prototyping/circuit-board-plotter/protomat-s63.htm) (From memory, roughly a $20K machine.)
    • Prototype being different from final design increases the total time spent designing, and if you're using high speed signals (USB, LVDS, 50 Ohm transmission lines) Really depend on the design and board geometry.

    I feel like I'm in the same boat as @Fred, And my opinion is biased against cheap in-house prototyping. Personally fabricating PCBs is not fun for me, designing / assembling and testing are the parts I find fun. So I'm more than happy to pay for someone else to do it reliably and work on another aspect of the project while I wait.


    I really like the results from @terjeio's laser plotter, I think that's a much better solution than milling.

  10. My personal opinion is not worth it. Based on the following points

    • Double sided boards are not easy
    • No plated through holes
    • Most of my designs are fully SMD (0603 or smaller) often with QFNs or TTSOPs
    • DIY setups require ALOT of time to tune/setup
    • Commercial solutions are VERY expensive (paying for the time to develop a reliable machine)
    • Minimum space is size of cutting bit (typically >0.4mm)
    • No soldermask
    • Prototyped designs are significantly different to Fabbed designs

    This might seem like I'm complaining about things that don't matter. But if you compare a milled PCB and a professionally fabbed PCB from a batch Chinese service, they're worlds apart.


    I've played with Toner transfer, photosensitive ink transfer, and milled PCBs. Out of all photo-sensitive was the best most repeatable, but my lab space is not setup for making PCBs. It just takes me too long to setup and pack down all the equipment. Photo-sensitive has the advantage that the same process repeated will give you a solder mask.


    We have a LPRF ProMat S63 at uni, it's an amazing machine. But the upfront cost and cost for PCB blanks and operating costs (broken bits mostly) don't make it an attractive offer. I would much rather timeline a 5 day wait for PCBs from china into my projects.


    Just my thoughts, If your prototypes are primarily single side, with larger components. Or if you use alot of through hole parts. It should be a good fit.




    My fix was actually slightly different though. I mention this in case it may help new players understand things better. I keep the ~ bit operator inside of brackets for the sake of operator seperation. Like so.

            P1SEL &= (~BIT0) + (~BIT5);             // Set P1.0 and P1.5 SEL as GPIO
            P1DIR &= (~BIT0) + (~BIT5);             // Set P1.0 and P1.5 SEL as Input
            P1IES |= BIT0 + BIT5;                   // Falling Edge 1 -> 0
            P1IFG &= (~BIT0) + (~BIT5);             // Clear interrupt flag for P1.5
            P1IE |=  BIT0 + BIT5;                   // Enable interrupt for P1.5


    Isn't this still producing the wrong result??


    After negating , if you add you'll get an overflow....

    (~BIT0) + (~BIT5) == (~0x01) + (~0x20) == (0xFE) + (0xDF) == (0x1DD)

    If you insist on negating within brackets then you should be using AND operations to receive the required result, not ADD.

    (~BIT0) & (~BIT5) == (~0x01) & (~0x20) == (0xFE) & (0xDF) == (0xDE)
  12. Achieving ultra-low power can sometimes take a bit of work. It might be helpful to see a circuit diagram. If you have a pull-down resistor with a logic HIGH applied you will have power loss through that resistor (for example your serial lines?)


    Are there any other parts fitted on your custom PCB?

    Just having the debugger connected adds additional power loss, even when the MSP is in LPM4.

  13. I'm curious about this snippet of code. Your use of brackets is confusing to me. Particularly these 3 lines.


            P1SEL &= (~BIT0 + BIT5);                // Set P1.0 and P1.5 SEL as GPIO
            P1DIR &= (~BIT0 + BIT5);                // Set P1.0 and P1.5 SEL as Input
            P1IFG &= (~BIT0 + BIT5);                // Clear interrupt flag for P1.5


    To me this feels like it will be performing function A. Which results in an overflow. Is this your intent?

    A. (~BIT0 + BIT5) == (~0x01 + 0x20) == (0xFE + 0x20) == (0x11E) == 0x1E <- After it's put into a 8bit register
    B. ~(BIT0 + BIT5) == ~(0x01 + 0x20) == ~(0x21) == 0xDE

    Doesn't look related to your issue. But still looks like a bug.

  14. Polyurethane parts have come up nicely.




    Main advantages of this method of rapid prototyping

    • Part cost is low these use about $0.05 of polyurethane resin.
    • Parts can easily be coloured using dyes. (as demonstrated)
    • Very little time needed for each cast (about 5 minutes) 1-2 Hour cure time
    • 1-1 replica to original part.

    Of course you need to invest the time and money to make the silicone molds to begin with. So for a single part 3d printing is often the preferred approach.





    The parts are a perfect fit over the button and LEDs.





  15. I feel some serious tool-envy :wub:


    Thanks, But don't be fooled. My setup takes quite awhile to setup. And I'm still learning all the time, The first pass I made on this cutout skipped steps somehow, ruining this enclosure.

    I'd love to own some better tools ;) But I'm going to make use of what I have right now.


    But I took the opportunity to try some cool stuff. (note the mis-aligned cutouts at the bottom and the duplicates on the far side.)



    Infill on my engravings and engraved pixel fonts!



    Getting the hang of F360, slowly.




    Working on some custom parts now. Using a molding technique using milled ren-shape, silicone and polyurethane.

    Mold model



    Blank ren-shape



    Mid milling


  16. Got my enclosures today. That means I now have all the hardware parts for this batch.


    I've been playing around with Fusion 360 instead of Rhino, mainly due to the integrated CAM processor. Also it has easy to use rendering stuff out of the box too.


    This is the reason I love companies that provide 3d CAD files. I can define some simple stroke text, and Fusion 360 will project it over the 3d curvature of the part.



    My CNC setup is in dis-array. The setup is sub optimal.



    But I think the results speak for themselves.



    I want to experiment with filling the engravings with a paint to make them stand out.

  17. ok, so i can either move interrupt vector in the RAM. (i d'ont know how to do, i'll try this solution after, ), or i can either move the interrupt vectors in the FRAM.

    For keeping them into the FRAM, how doing?i don't understand what you said by: "you will need to copy these into the alternative area within the RAM"& "activate the alternative interrupt setting before enabling interrupts." ?


    You can't move the interrupt vectors around in FRAM, the physical address is hard coded to a specific interrupt. So address 0xFFFE is always the reset vector.

    If you want to alter the interrupt table, for a boot loader lets say, you can use an alternative address for these interrupts that exists in RAM, it's still a hardcoded memory location for each interrupt vector, 0x23FE for reset. But you can easily change where the interrupts will go, because they're in RAM.

  18. Just did a test in CCS on my MSP-EXP430FR5969

    #include <msp430.h>
    #include <stdint.h>
    // Timer0_A1 Interrupt Vector (TAIV) handler
    #pragma vector=401
    __interrupt void ram_handler(void)
      switch(__even_in_range(TA0IV, TA0IV_TAIFG))
        case TA0IV_NONE:   break;               // No interrupt
        case TA0IV_TACCR1: break;               // CCR1 not used
        case TA0IV_TACCR2: break;               // CCR2 not used
        case TA0IV_3:      break;               // reserved
        case TA0IV_4:      break;               // reserved
        case TA0IV_5:      break;               // reserved
        case TA0IV_6:      break;               // reserved
        case TA0IV_TAIFG:                       // overflow
          P4OUT ^= BIT6;
        default: break;
    #pragma vector=400
    __interrupt void default_handler(void)
    const uint16_t new_IV[64] = {
    		&default_handler, /* .int00    */
    		&default_handler, /* .int01    */
    		&default_handler, /* .int02    */
    		&default_handler, /* .int03    */
    		&default_handler, /* .int04    */
    		&default_handler, /* .int05    */
    		&default_handler, /* .int06    */
    		&default_handler, /* .int07    */
    		&default_handler, /* .int08    */
    		&default_handler, /* .int09    */
    		&default_handler, /* .int10    */
    		&default_handler, /* .int11    */
    		&default_handler, /* .int12    */
    		&default_handler, /* .int13    */
    		&default_handler, /* .int14    */
    		&default_handler, /* .int15    */
    		&default_handler, /* .int16    */
    		&default_handler, /* .int17    */
    		&default_handler, /* .int18    */
    		&default_handler, /* .int19    */
    		&default_handler, /* .int20    */
    		&default_handler, /* .int21    */
    		&default_handler, /* .int22    */
    		&default_handler, /* .int23    */
    		&default_handler, /* .int24    */
    		&default_handler, /* .int25    */
    		&default_handler, /* .int26    */
    		&default_handler, /* .int27    */
    		&default_handler, /* .int28    */
    		&default_handler, /* .int29    */
    		&default_handler, /* AES256    */
    		&default_handler, /* RTC       */
    		&default_handler, /* PORT4     */
    		&default_handler, /* PORT3     */
    		&default_handler, /* TIMER3_A1 */
    		&default_handler, /* TIMER3_A0 */
    		&default_handler, /* PORT2     */
    		&default_handler, /* TIMER2_A1 */
    		&default_handler, /* TIMER2_A0 */
    		&default_handler, /* PORT1     */
    		&default_handler, /* TIMER1_A1 */
    		&default_handler, /* TIMER1_A0 */
    		&default_handler, /* DMA       */
    		&default_handler, /* USCI_A1   */
    		&ram_handler, /* TIMER0_A1 */
    		&default_handler, /* TIMER0_A0 */
    		&default_handler, /* ADC12     */
    		&default_handler, /* USCI_B0   */
    		&default_handler, /* USCI_A0   */
    		&default_handler, /* WDT       */
    		&default_handler, /* TIMER0_B1 */
    		&default_handler, /* TIMER0_B0 */
    		&default_handler, /* COMP_E    */
    		&default_handler, /* UNMI      */
    		&default_handler, /* SYSNMI    */
    		&default_handler, /* .reset    */
    int main(void)
      WDTCTL = WDTPW | WDTHOLD;                 // Stop WDT
      // Configure GPIO
      P1DIR |= BIT0;
      P4DIR |= BIT6;
      P1OUT &= ~BIT0;
      P4OUT &= ~BIT6;
      PJSEL0 |= BIT4 | BIT5;
      // Disable the GPIO power-on default high-impedance mode to activate
      // previously configured port settings
      PM5CTL0 &= ~LOCKLPM5;
      // Setup XT1
      CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
      CSCTL1 = DCOFSEL_6;                       // Set DCO to 8MHz
      CSCTL3 = DIVA__1 | DIVS__2 | DIVM__2;     // Set all dividers
      CSCTL4 &= ~LFXTOFF;
        CSCTL5 &= ~LFXTOFFG;                    // Clear XT1 fault flag
        SFRIFG1 &= ~OFIFG;
      }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag
      CSCTL0_H = 0;                             // Lock CS registers
      TA0CTL = TASSEL__ACLK | MC__CONTINUOUS | TACLR | TAIE; // ACLK, contmode, clear TAR
                                                // enable interrupt
      /* Copy IV's into RAM */
      uint16_t* RAM_IV = 0x2390; /* Note start address of 0x90 not 0x80 */
      uint8_t counter;
      for(counter = 0 ; counter < 64; counter++)
    	  RAM_IV[counter] =  new_IV[counter];
      __bis_SR_register(LPM3_bits | GIE);       // Enter LPM3, enable interrupts
      __no_operation();                         // For debugger
    // Timer0_A1 Interrupt Vector (TAIV) handler
    #pragma vector=TIMER0_A1_VECTOR
    __interrupt void TIMER0_A1_ISR(void)
      switch(__even_in_range(TA0IV, TA0IV_TAIFG))
        case TA0IV_NONE:   break;               // No interrupt
        case TA0IV_TACCR1: break;               // CCR1 not used
        case TA0IV_TACCR2: break;               // CCR2 not used
        case TA0IV_3:      break;               // reserved
        case TA0IV_4:      break;               // reserved
        case TA0IV_5:      break;               // reserved
        case TA0IV_6:      break;               // reserved
        case TA0IV_TAIFG:                       // overflow
          P1OUT ^= BIT0;
        default: break;

    And you need to alter the Linker script to instruct the compiler to leave the RAM space clear

        SFR                     : origin = 0x0000, length = 0x0010
        PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
        PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100
        RAM                     : origin = 0x1C00, length = 0x0780 /* <<- Altered */
        INFOA                   : origin = 0x1980, length = 0x0080
        INFOB                   : origin = 0x1900, length = 0x0080
        INFOC                   : origin = 0x1880, length = 0x0080
        INFOD                   : origin = 0x1800, length = 0x0080
        FRAM                    : origin = 0x4400, length = 0xBB80
        FRAM2                   : origin = 0x10000,length = 0x4000

    By commenting out the line below you can switch between the FRAM IV's and the RAM IV's


    Hope this helps.

  19. I personally have not looked into it in too much detail. But from what I've read the interrupt vectors are by default fixed at the top* of FRAM 0xFF80 - 0xFFFF Or if the Alternative vectors are selected at the top of RAM 0x2380 - 0x23FF.


    If you would like to have 0xFF00 - 0xFF7F mapped to interrupt vector you will need to copy these into the alternative area within the RAM and then activate the alternative interrupt setting before enabling interrupts.

  20. post-274-0-72372200-1469658488_thumb.jpg


    @Fred It would be nice to see how much of a performance gain I get with/without. The LNA is already designed to only amplify within the range of GPS + GLONASS frequencies. As mentioned just bypassing the filter with a bodge wire seems to work quite well.




    I did a very quick side by side test, and the new uBlox MAX M8Q with a 25x25mm antenna shows twice the satellites than the old g-top modules, all with improved signal strength.


    For reference here is a comparison of the path antenna sizes.


    (Left to right: 12x12mm, 25x25mm, 35x25mm)


    The 35x35mm was in stock at digikey so I bought 2 to play around with and compare. The 25x25mm is what I plan to use for this version.


  21. I have a PCB soldered up. Everything working as expected, except no GPS acquisition.


    After some re-soldering and fault finding. Found the SAW filter wasn't working. The antenna seems to operate fine without it. (I imagine the GPS module has it's own internal SAW filter....)


    I fell into a newbie trap. Here is a page from the B8813 datasheet.



    Notice the "Bottom view" text, because I did not when I made the footprint.


  • Create New...