• PCB Prototype Sent for Manufacture.

    Joshua Elsdon08/21/2017 at 21:51 0 comments

    Just a quick update. This project and a number of my other ones have been sent off to the board house. Currently it will only be rigid PCB, such that it is cheap to make mistakes. If all goes well then the next version will be flex. 

    Now that I have sent them away I will make the files public. You can find them HERE

  • PCB

    Joshua Elsdon08/18/2017 at 21:37 0 comments

    Hello, 

    Just a small update. The PCB is basically done for the watch. As I think was mentioned before, the watch will eventually be constructed on flex PCB, with sections made rigid with stiffening panels on the back. 

    The flex cable to the OLED display will post through the long hole on the right. The circular object on the top left is the vibration motor. Most of the rest of the design are various power supply and management circuits. At the bottom of the above image you can see the high brightness white LEDs, which I think will be a very useful feature, as we cannot see in the dark (oh wait, with this watch we can ;) ) 

    On this image the block on the right is the thermal camera. The one in the middle is the battery. The oled is not rendered here, but it will (I guess somewhat obviously) sit on-top of the battery. On the left is the d-pad style switch with centre click. Next to it are the visual spectrum light sensor for detecting ambient light, so that you don't blind yourself in the middle of the night with the super bright OLED. Adjacent to this is a UV index sensor. I was birthed with the ability to burn in the sun very quickly, now I will be able to quantify the sun by sticking my arm out briefly from the shadows so I can have data on what I am missing out on. 

    You may notice that there is a large flange all the way around the PCB, this is to simplify the waterproofing process. If the PCB goes all the way to the edge every where there will be no 'seem' to form a channel through the rubber gaskets, of which there will be many. Many many gaskets. 

    I will be prototyping this on rigid board first. So wish me luck. (the small section near the slot for the OLED looks rather snap-able eh.)

  • Getting the Thermal Camera to Work

    Joshua Elsdon08/03/2017 at 13:04 0 comments

    Okidoke, so the last couple of days have been spent getting the thermal camera to work correctly. This surprised me as there is decent sample code specifically for ChibiOS on the GroupGets Github. I am not entirely sure what was going wrong. My best guess was that there was a mixture of small bugs compounding each other, most likely in the set up of the GPIOs and the SPI port (as the default port in all the examples is the one that is driving the OLED). These bugs were sorted after many hours of perturbing the code. 

    Once I have a buffer with the image in it's native 14bit integer type (padded to short ints) I needed to render this into an image that looks sensible. This was achieved by  using the min and the max values from the previous frame (ain't nobody got time to prescan the newest image), and then linearly interpolating between blue -> green -> red in RGB 565 format. The results looked nice, though I could only render half of the frames delivered from the camera due to the time it took to process this. 

    Changing the maths from floating point to integer saved the day, later I will precalculate some nice looking colour lookup tables. I thought floating point would be fine as the STM32L432 has an FPU, but it turns out I will need to pull every drop of performance to render all frames on the higher resolution Lepton 3 I intend to use in the final design. 

    I still need to implement scaling so I can fill the whole screen (and downscale on the new sensor). Likely I will only be able to achieve 4:3 scaling ratio, as this can be interpolated using only bit shifting. I will waste a few pixels, as this will give me a 90x120 image and the OLED is 96x128. I can probably think of some simple GUI to make use of the extra space. 

    Any way I will be able to clean my code up for public release now that the core functionality is functional. Here is a picture for you all to enjoy! 

  • Getting the OLED to work

    Joshua Elsdon07/27/2017 at 22:51 0 comments

    Today was a very long day.... I got started with ChibiOS and uGFX and they seemed to want to give me fight. First the good news. ChibiStudio is very good as far as being set up quickly. I had set up a similar workspace for my micro-robots project, ChibiStudio did the same thing much quicker. 

    The primary thing that was needed was to sort out the board_SDD1351.h file. Mine ended up like this (There is someone else's code in here but the hours of messing with the code have made me loose the reference.)

    /*
     * This file is subject to the terms of the GFX License. If a copy of
     * the license was not distributed with this file, you can obtain one at:
     *
     *              http://ugfx.org/license.html
     */
    #ifndef _GDISP_LLD_BOARD_H
    #define _GDISP_LLD_BOARD_H
    #define SPI_DRIVER (&SPID1)
    #define SPI_PORT GPIOA
    #define SCK_PAD  5  //PA5
    #define MISO_PAD 6 //PA6
    #define MOSI_PAD 12 //PA7
    #define CS_PORT     GPIOB
    #define RESET_PORT  GPIOA
    #define DNC_PORT    GPIOA
    #define CS_PAD     4        // PB4 --  0 = chip selected
    #define RESET_PAD  10        // PA10 -- 0 = reset
    #define DNC_PAD    9        // PA9 -- control=0, data=1 -- DNC or D/C
    // SPI setup ajust " SPI_BaudRatePrescaler_X" to set SPI speed.
    // Peripherial Clock 42MHz SPI2 SPI3
    // Peripherial Clock 84MHz SPI1                                SPI1        SPI2/3
    #define SPI_BaudRatePrescaler_2         ((uint16_t)0x0000) //  42 MHz      21 MHZ
    #define SPI_BaudRatePrescaler_4         ((uint16_t)0x0008) //  21 MHz      10.5 MHz
    #define SPI_BaudRatePrescaler_8         ((uint16_t)0x0010) //  10.5 MHz    5.25 MHz
    #define SPI_BaudRatePrescaler_16        ((uint16_t)0x0018) //  5.25 MHz    2.626 MHz
    #define SPI_BaudRatePrescaler_32        ((uint16_t)0x0020) //  2.626 MHz   1.3125 MHz
    #define SPI_BaudRatePrescaler_64        ((uint16_t)0x0028) //  1.3125 MHz  656.25 KHz
    #define SPI_BaudRatePrescaler_128       ((uint16_t)0x0030) //  656.25 KHz  328.125 KHz
    #define SPI_BaudRatePrescaler_256       ((uint16_t)0x0038) //  328.125 KHz 164.06 KHz
    static SPIConfig spi_cfg = {
            NULL,
            CS_PORT,
            CS_PAD,
            SPI_BaudRatePrescaler_16 //AJUST SPEED HERE..
    };
    static inline void init_board(GDisplay *g) {
        (void) g;
        //g->board = 0;
                    //Set up the pins..
            palSetPadMode(SPI_PORT, SCK_PAD,  PAL_MODE_ALTERNATE(5));
            palSetPadMode(SPI_PORT, MOSI_PAD,  PAL_MODE_ALTERNATE(5));
            palSetPadMode(SPI_PORT, MISO_PAD,  PAL_MODE_ALTERNATE(5));
            palSetPadMode(RESET_PORT, RESET_PAD, PAL_MODE_OUTPUT_PUSHPULL);
            palSetPadMode(CS_PORT, CS_PAD, PAL_MODE_OUTPUT_PUSHPULL);
            palSetPadMode(DNC_PORT, DNC_PAD, PAL_MODE_OUTPUT_PUSHPULL);
                    //Set pins.
            palSetPad(CS_PORT, CS_PAD);
            palSetPad(RESET_PORT, RESET_PAD);
            palClearPad(DNC_PORT, DNC_PAD);
                    //Start SPI1 with our config.
                    spiStart(SPI_DRIVER, &spi_cfg);
    }
    static inline void post_init_board(GDisplay *g) {
        (void) g;
    }
    static inline void setpin_reset(GDisplay *g, bool_t state) {
        (void) g;
        palWritePad(RESET_PORT, RESET_PAD, !state);
    }
    static inline void set_backlight(GDisplay *g, uint8_t percent) {
        (void) g;
        (void) percent;
    }
    static inline void acquire_bus(GDisplay *g) {
        (void) g;
        spiSelect(SPI_DRIVER);
    }
    static inline void release_bus(GDisplay *g) {
        (void) g;
        spiUnselect(SPI_DRIVER);
    }
    static inline void write_cmd(GDisplay *g, uint8_t index) {
        static uint8_t  sindex;
        (void) g;
        palClearPad(DNC_PORT, DNC_PAD);
        sindex = index;
        spiSend(SPI_DRIVER, 1, &sindex);
    }
    static inline void write_data(GDisplay *g, uint8_t data) {
        static uint8_t  sdata;
        (void) g;
        palSetPad(DNC_PORT, DNC_PAD);
        sdata = data;
        spiSend(SPI_DRIVER, 1, &sdata);
    }
    static inline void setreadmode(GDisplay *g) {
       (void) g;
    }
    static inline void setwritemode(GDisplay *g) {
       (void) g;
    }
    static inline uint16_t read_data(GDisplay *g) {
        (void) g;
        return 0;
    }
    #endif /* _GDISP_LLD_BOARD_H */
    

    By default the uGFX library seems to schedule single pixels using the DMA hardware, which is very inefficient. This allows me to fill a page at 3FPS or so. Luckily the SPI support code in ChibiOS seems to support DMA out of the box, so it will just be a case of piping a buffer into the appropriate API call. I just need to work out how this is supposed to be integrated with...

    Read more »

  • Project Outline

    Joshua Elsdon07/25/2017 at 19:00 0 comments

    Hello, 


    If you have gotten this far you probably know that I intend to build a watch. This is correct. I can also assume that this information alone is not enough to satiate your curiosity, so here I will provide a few cheeky details of my plan. 

    Goals

    The watch must be:

    • Small enough people will not notice that this is 'homemade' from a distance, and sleek enough that people are not repulsed by it when close up. 
    • Run on a charge for about 1 year, the same as my current wristwatch. The assumption would be that only the time keeping functions would count towards this, the other features should be pretty intermittently used. Also if you have a long thermal camera session you would expect to charge the device you are using anyway. 
    • I want it to be waterproof. This is something that I have not seen in any other DIY watch designs (and few commercial watches with cool features either). This is important as I self identify as "Someone who has a watch", and time without a watch gives me tremendous separation anxiety. Therefore I should be able to wear it in the shower and while washing hands etc. Diving to 100m will remain on the TODO list indefinitely.  
    • Be Dumb. I solemnly swear that this project will not become an internet of thing. Nor will it think itself clever enough to have the prefix "smart... " . It will have a predefined list of features, it will do them, and nothing more. No expansion interfaces, no communication. No infinite list of TODOs. Can you remember the last time you 'finished' a project. Me neither. 

    Hardware 

    You can view the hardware in its unfinished state (Unless you are reading this in the future, in which case, the project is done and the files are gorgeous) here. Currently the hardware is based on 3 main components. Processor: STM32L432, Camera: FLIR Lepton,  Screen: 1.27" OLED ssd1351. 

    Additionally to these main components there will be a light sensor for appropriately dimming the display. A UV index sensor, because I am pale and I drink SPF50+ to survive. And some bright LED's for convenient wrist mounted light when you are under a desk renovating a desktop. 

    In order to allow the camera to point outward from the user I will be using a flex PCB with rigid sections. There will be 3 parts: the thermal camera pointing out, the watch face on top of the wrist, and the push buttons facing the user.

    Software

    I will be attempting to use ChibiOS and uGFX primarily. I know that I will need to stretch the STM32 pretty hard to get the Camera read out and the screen update to all meet their timing constraints. Also if I want to run some simple games then having a nice graphics library is nice to have.    

    Conclusion

    Like / follow etc if you would like to see a watch with a thermal camera integrated.