Jump to content

Recommended Posts

Posted

Hello friends,

I'm trying to use multiple displays (one SSD1963 and two ILIILI9341 based screens). I followed the steps in the wiki and am running into the following error: 

Linking build/ch.elf
build/obj/gdisp_lld_ILI9341.o (symbol from plugin): In function `GDISPVMT_OnlyOne':
(.text+0x0): multiple definition of `GDISPVMT_OnlyOne'
build/obj/gdisp_lld_SSD1963.o (symbol from plugin):(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
make: *** [build/ch.elf] Error 1

 

I looked through the source and found that this is because GDISP_DRIVER_LIST isn't defined. I define that, but a rule prevents me from compiling: GDISP Multiple Drivers: You can't specify both GDISP_TOTAL_DISPLAYS and GDISP_DRIVER_LIST. 

 

Am I setting multiple displays up wrong?

Posted

Simply remove the GDISP_TOTAL_DISPLAYS setting from your gfxconf.h. That setting is designed for when you have multiple displays all using the one controller type.

Posted (edited)

I was able to get this working. Here's some info for those who need it.

 

You only specify GDISP_DRIVER_LIST, contrary to what the Wiki suggests. It must be outdated. Example:

#define GDISP_DRIVER_LIST                            GDISPVMT_SSD1963, GDISPVMT_ILI9341, GDISPVMT_ILI9341

 

You can then write your board file accordingly. In my example, I have SSD1963 as 0, ILI9341 as 1 and 2. You can find a hacked up (but working) example for an STM32F4 below.

#ifndef _GDISP_LLD_BOARD_H
#define _GDISP_LLD_BOARD_H
//**** ILI9341 on SPI1. TESTED on STM32L1, STM32F1 AND STM32F4.
// Pin & SPI setup
#define SPI_METHOD_IRQ		    1
#define SPI_METHOD_POLLING		2
#define SPI_METHOD			SPI_METHOD_POLLING
// SPI1
#define SPI_DRIVER_1 (&SPID1)
#define SPI_PORT_1 GPIOA
#define SCK_PAD_1  5
#define MISO_PAD_1 6
#define MOSI_PAD_1 7

#define CS_PORT_1     GPIOA
#define RESET_PORT_1  GPIOA
#define DNC_PORT_1    GPIOA
#define CS_PAD_1     2
#define DNC_PAD_1    4
#define RESET_PAD_1  3


#define SPI_DRIVER_2 (&SPID2)
#define SPI_PORT_2 GPIOB
#define SCK_PAD_2  13
#define MISO_PAD_2 14
#define MOSI_PAD_2 15

#define CS_PORT_2     GPIOB
#define RESET_PORT_2  GPIOB
#define DNC_PORT_2    GPIOB
#define CS_PAD_2     5
#define DNC_PAD_2    6
#define RESET_PAD_2  7

// 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_cfg1 = {NULL, CS_PORT_1, CS_PAD_1,
                             SPI_BaudRatePrescaler_4 //AJUST SPEED HERE..
};

static SPIConfig spi_cfg2 = {NULL, CS_PORT_2, CS_PAD_2,
                             SPI_BaudRatePrescaler_2 //AJUST SPEED HERE..
};

static inline void init_board(GDisplay *g) {
  (void)g;
  g->board = 0;
  switch (g->systemdisplay) {
  case 1:
    //Set up the pins..
    palSetPadMode(CS_PORT_1, CS_PAD_1, PAL_MODE_OUTPUT_PUSHPULL);
    palSetPadMode(SPI_PORT_1, SCK_PAD_1, PAL_MODE_ALTERNATE(5));
    palSetPadMode(SPI_PORT_1, MISO_PAD_1, PAL_MODE_ALTERNATE(5));
    palSetPadMode(SPI_PORT_1, MOSI_PAD_1, PAL_MODE_ALTERNATE(5));

    palSetPadMode(RESET_PORT_1, RESET_PAD_1, PAL_MODE_OUTPUT_PUSHPULL);
    palSetPadMode(DNC_PORT_1, DNC_PAD_1, PAL_MODE_OUTPUT_PUSHPULL);

    //Set pins.
    palSetPad(CS_PORT_1, CS_PAD_1);
    palSetPad(RESET_PORT_1, RESET_PAD_1);
    palClearPad(DNC_PORT_1, DNC_PAD_1);

    //Start SPI1 with our config.
    spiStart(SPI_DRIVER_1, &spi_cfg1);
    spiSelectI(SPI_DRIVER_1); /* Slave Select assertion.          */
    break;

  case 2:
    //Set up the pins..
    palSetPadMode(CS_PORT_2, CS_PAD_2, PAL_MODE_OUTPUT_PUSHPULL);
    palSetPadMode(SPI_PORT_2, SCK_PAD_2, PAL_MODE_ALTERNATE(5));
    palSetPadMode(SPI_PORT_2, MISO_PAD_2, PAL_MODE_ALTERNATE(5));
    palSetPadMode(SPI_PORT_2, MOSI_PAD_2, PAL_MODE_ALTERNATE(5));

    palSetPadMode(RESET_PORT_2, RESET_PAD_2, PAL_MODE_OUTPUT_PUSHPULL);
    palSetPadMode(DNC_PORT_2, DNC_PAD_2, PAL_MODE_OUTPUT_PUSHPULL);

    //Set pins.
    palSetPad(CS_PORT_2, CS_PAD_2);
    palSetPad(RESET_PORT_2, RESET_PAD_2);
    palClearPad(DNC_PORT_2, DNC_PAD_2);

    //Start SPI2 with our config.
    spiStart(SPI_DRIVER_2, &spi_cfg2);
    spiSelectI(SPI_DRIVER_2); /* Slave Select assertion.          */
    break;
  }

}

static inline void post_init_board(GDisplay *g) {
  (void)g;
}

static inline void setpin_reset(GDisplay *g, bool_t state) {
  (void)g;
  switch (g->systemdisplay) {
  case 1:
    palWritePad(RESET_PORT_1, RESET_PAD_1, !state);
    break;
  case 2:
    palWritePad(RESET_PORT_2, RESET_PAD_2, !state);
    break;
  }
}

static inline void set_backlight(GDisplay *g, uint8_t percent) {
  (void)g;
  (void)percent;
}

static inline void acquire_bus(GDisplay *g) {
  (void)g;
  switch (g->systemdisplay) {
  case 1:
    spiSelectI(SPI_DRIVER_1);
    break;
  case 2:
    spiSelectI(SPI_DRIVER_2);
    break;
  }
}

static inline void release_bus(GDisplay *g) {
  (void)g;
  switch (g->systemdisplay) {
  case 1:
    spiUnselectI(SPI_DRIVER_1);
    break;
  case 2:
    spiUnselectI(SPI_DRIVER_2);
    break;
  }
}

static inline void write_index(GDisplay *g, uint8_t index) {
  (void)g;
  switch (g->systemdisplay) {
  case 1:
    palClearPad(DNC_PORT_1, DNC_PAD_1);
#if SPI_METHOD == SPI_METHOD_IRQ
    spiSend(SPI_DRIVER_1, 1, &index);
#elif SPI_METHOD == SPI_METHOD_POLLING
    spiPolledExchange(SPI_DRIVER_1, index);
#endif
    palSetPad(DNC_PORT_1, DNC_PAD_1);
    break;

  case 2:
    palClearPad(DNC_PORT_2, DNC_PAD_2);
#if SPI_METHOD == SPI_METHOD_IRQ
    spiSend(SPI_DRIVER_2, 1, &index);
#elif SPI_METHOD == SPI_METHOD_POLLING
    spiPolledExchange(SPI_DRIVER_2, index);
#endif
    palSetPad(DNC_PORT_2, DNC_PAD_2);
    break;
  }
}

static inline void write_data(GDisplay *g, uint8_t data) {
  (void)g;

  switch (g->systemdisplay) {
  case 1:
#if SPI_METHOD == SPI_METHOD_IRQ
    spiSend(SPI_DRIVER_1, 1, &data);
#elif SPI_METHOD == SPI_METHOD_POLLING
    spiPolledExchange(SPI_DRIVER_1, data);
#endif
    break;
  case 2:
#if SPI_METHOD == SPI_METHOD_IRQ
    spiSend(SPI_DRIVER_2, 1, &data);
#elif SPI_METHOD == SPI_METHOD_POLLING
    spiPolledExchange(SPI_DRIVER_2, data);
#endif
    break;

  }
}

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 */

 

Edited by King John
Posted

Another trick you can use is in the init_board routine set the g->board field to a structure that contains register pointers and pin definitions for that display. Each display has its own g->board field.

In any other routine you can use that field to access the structure and thus not have to switch on every operation.

Posted

I finally had some time to clean up that board file. Hopefully this helps someone out there in the future.

 

#ifndef _GDISP_LLD_BOARD_H
#define _GDISP_LLD_BOARD_H
//**** ILI9341 on SPI1. TESTED on STM32L1, STM32F1 AND STM32F4.
// Pin & SPI setup
#define SPI_METHOD_IRQ		    1
#define SPI_METHOD_POLLING		2
#define SPI_METHOD			SPI_METHOD_POLLING

// 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

//macro for functions
#define iliboard ((ILI9341Config*)g->board)

typedef struct ILI9341Config
{
                                      SPIDriver* spid;
                                      ioportid_t spiport;
                                      short sck;
                                      short miso;
                                      short mosi;

                                      ioportid_t csport;
                                      short cs;
                                      ioportid_t resetport;
                                      int reset;
                                      ioportid_t dncport;
                                      short dnc;
                                      SPIConfig spicfg;
} ILI9341Config;

static ILI9341Config s1conf = {
                               .spid = &SPID1,
                               .spiport = GPIOA,
                               .sck = 5,
                               .miso = 6,
                               .mosi = 7,

                               .csport = GPIOA,
                               .cs = 2,
                               .dncport = GPIOA,
                               .dnc = 3,
                               .resetport = GPIOA,
                               .reset = 4,
                               .spicfg = {NULL, GPIOA, 2, SPI_BaudRatePrescaler_4}
};

static ILI9341Config s2conf = {
                               .spid = &SPID2,
                               .spiport = GPIOB,
                               .sck = 13,
                               .miso = 14,
                               .mosi = 15,

                               .csport = GPIOE,
                               .cs = 0,
                               .dncport = GPIOB,
                               .dnc = 6,
                               .resetport = GPIOB,
                               .reset = 7,
                               //same as GPIO and port of above CS
                               .spicfg = {NULL, GPIOE, 0, SPI_BaudRatePrescaler_2}
};

static inline void init_board(GDisplay *g) {
  (void)g;
  switch (g->systemdisplay) {
  case 1:
    g->board = &s1conf;
    break;

  case 2:
    g->board = &s2conf;
    break;
  }

  ILI9341Config* conf = g->board;

  //Set up the pins..
  //Might want to setup a conditional here for if it's SPID3, as that's supposed to be alternate mode 6
  palSetPadMode(conf->spiport, conf->sck, PAL_MODE_ALTERNATE(5));
  palSetPadMode(conf->spiport, conf->miso, PAL_MODE_ALTERNATE(5));
  palSetPadMode(conf->spiport, conf->mosi, PAL_MODE_ALTERNATE(5));

  palSetPadMode(conf->csport, conf->cs, PAL_MODE_OUTPUT_PUSHPULL);
  palSetPadMode(conf->resetport, conf->reset, PAL_MODE_OUTPUT_PUSHPULL);
  palSetPadMode(conf->dncport, conf->dnc, PAL_MODE_OUTPUT_PUSHPULL);

  //Set pins.
  palSetPad(conf->csport, conf->cs);
  palSetPad(conf->resetport, conf->reset);
  palClearPad(conf->dncport, conf->dnc);

  //Start SPI driver with our config.
  spiStart(conf->spid, &(conf->spicfg));
  spiSelectI(conf->spid); /* Slave Select assertion.          */

}

static inline void post_init_board(GDisplay *g) {
  (void)g;
}

static inline void setpin_reset(GDisplay *g, bool_t state) {
  (void)g;
  palWritePad(iliboard->resetport, iliboard->reset, !state);
}

static inline void set_backlight(GDisplay *g, uint8_t percent) {
  (void)g;
  (void)percent;
}

static inline void acquire_bus(GDisplay *g) {
  (void)g;
  spiSelectI(iliboard->spid);
}

static inline void release_bus(GDisplay *g) {
  (void)g;
  spiUnselectI(iliboard->spid);
}

static inline void write_index(GDisplay *g, uint8_t index) {
  (void)g;
  palClearPad(iliboard->dncport, iliboard->dnc);
#if SPI_METHOD == SPI_METHOD_IRQ
  spiSend(iliboard->spid, 1, &index);
#elif SPI_METHOD == SPI_METHOD_POLLING
  spiPolledExchange(iliboard->spid, index);
#endif
  palSetPad(iliboard->dncport, iliboard->dnc);
}

static inline void write_data(GDisplay *g, uint8_t data) {
  (void)g;

#if SPI_METHOD == SPI_METHOD_IRQ
  spiSend(iliboard->spid, 1, &data);
#elif SPI_METHOD == SPI_METHOD_POLLING
  spiPolledExchange(iliboard->spid, data);
#endif
}

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 */

 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...