Close

Getting the OLED to work

A project log for Thermal Watch

An attempt to design a watch that integrates a thermal camera, whilst remaining sleek.

joshua-elsdonJoshua Elsdon 07/27/2017 at 22:510 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 uGFX such that I do not end up with a burden of maintenance for a rubbish hack. Doing so should get the performance up to around 30FPS in my estimation. 

I have yet to really get stuck in with ChibiOS itself, though it seems to have all the features you would hope for. This project should be pretty simple from an OS perspective. I intent to put the MCU into standby mode when not in use, which on wakeup starts the execution of code from the beginning (you can keep a section of SRAM and the RTC still runs). I can just spawn a new application specific thread, then kill the whole system and start from scratch when going 'back' to the watch face. 

Any way I will upload a git when I fully understand all the files that need to be included and can minimalise it.  

Discussions