Jump to content

Multiple Displays Trouble


King John

Recommended Posts

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?

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

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