Jump to content

Recommended Posts

Posted

Hello,

I wanted to create a EADOGS102 driver. It uses SPI2 and I checked working SPI using a scope.

However the font demo is not working for me using my driver. Do I need to implement board_init()?

Bye bye and thx a lot

Posted

Hello hekthe and welcome to the community!

Currently there is no driver for the EADOGS102 in the µGFX repository. Therefore you don't only have to implement the board files but you need to write the entire driver. All GDISP drivers are located under /src/drivers/gdisp/. There are many drivers so you have lots of examples available. However, we strongly recommend reading this article before you start writing your driver: http://wiki.ugfx.org/index.php?title=Di ... iver_Model

Please make sure that you strictly separate the hardware specific interface from the generic driver. The driver which goes to /src/drivers/gdisp/ must only contain driver specific things. All the hardware related functions to write to and read from the display need to go to the board file: http://wiki.ugfx.org/index.php?title=Board_File

Your display seems to be similar to the KS0108 that one of our community members implemented. Maybe you can take a look at that one as well: viewtopic.php?f=23&t=249

To test your driver we strongly recommend using the /demos/modules/gdisp/basics demo before you start using the fonts demo.

Please let us know should you have any other questions.

~ Tectu

Posted

Hello Tectu,

thank you for your welcome. I'm still puzzled why my EADOGS doesn't want to work. Where is my mistake?

Attached you will find my driver. My main.c looks like:

/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "ch.h"
#include "hal.h"
#include "test.h"
#include "gfx.h"

/*
* This is a periodic thread that does absolutely nothing except flashing
* a LED.
*/
static THD_WORKING_AREA(waThread1, 128);
static THD_FUNCTION(Thread1, arg) {

(void) arg;
chRegSetThreadName("blinker");
while (true) {
palSetPad(GPIOD, GPIOD_DEBUG_LED); /* Orange. */
chThdSleepMilliseconds(500);
palClearPad(GPIOD, GPIOD_DEBUG_LED); /* Orange. */
chThdSleepMilliseconds(500);

/**/
coord_t width, height;
coord_t i, j;

font_t font2 = gdispOpenFont("UI2*");

GDisplay *g = gdispGetDisplay(0);

// Get the screen size
width = gdispGetWidth();
height = gdispGetHeight();

gdispGDrawString((void*) g, width/2, height/2, "Hallo", font2, Black);

// Code Here
gdispDrawBox(10, 10, width / 2, height / 2, Black);
gdispFillArea(width / 2, height / 2, width / 2 - 10, height / 2 - 10,
Blue);
gdispDrawLine(5, 30, width - 50, height - 40, Black);

for (i = 5, j = 0; i < width && j < height; i += 7, j += i / 20)
gdispDrawPixel(i, j, Black);
/**/
}
}

/*
* Application entry point.
*/
int main(void) {

/*
* System initializations.
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
* - Kernel initialization, the main() function becomes a thread and the
* RTOS is active.
*/
halInit();
chSysInit();
gfxInit();
gdispClear(Black);

/*
* Creates the example thread.
*/
chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);




/*
* Normal main() thread activity, in this demo it does nothing except
* sleeping in a loop and check the button state.
*/
while (true) {
chThdSleepMilliseconds(500);
}
}

Thx a lot and bye bye

EADOGS102.zip

Posted

Now I can see data on the SPI via LA. LCD is still bllank. I used following main.c

#include "ch.h"
#include "hal.h"
#include "test.h"
#include "gfx.h"

/*
* This is a periodic thread that does absolutely nothing except flashing
* a LED.
*/
static THD_WORKING_AREA(waThread1, 128);
static THD_FUNCTION(Thread1, arg)
{
(void) arg;

chRegSetThreadName("blinker");

while (true) {
palTogglePad(GPIOD, GPIOD_DEBUG_LED); /* Orange. */
chThdSleepMilliseconds(500);
}
}

int main(void)
{
halInit();
chSysInit();
gfxInit();

gdispClear(Black);
gdispFillArea(0, 0, 20, 20, Black);

chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);

while (true) {
chThdSleepMilliseconds(500);
}
}

UC1701v2.zip

Posted (edited)

Inserting an endless loop immediately after the init sequence:

	
write_cmd(g, 0b10101111); /* Set Display Enable (end of init sequence) */

// Repeating endless the last command to check SPI
while(TRUE){
write_cmd(g, 0b10101111); /* Set Display Enable */
gfxSleepMilliseconds(1);
}

release_bus(g);

I see following.

Edited by Guest
Posted

When running the application code that you pasted earlier (the one that just calls the init functions and then gdispClear(Black/White)), can you please verify that the write_cmd() and the write_data() are being called/executed?

~ Tectu

Posted

Hi Tectu,

I checked this via DEBUG_LED connected to LA with following code in write_data():

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

palTogglePad(GPIOD, GPIOD_DEBUG_LED); /* Orange. */

acquire_bus(g);
palSetPad(GPIOB, GPIOB_LCD_RS); /* Set RS to write data. */
spiStart(&SPID2, &spi_cfg);
spiSelect(&SPID2);
gfxSleepMicroseconds(1);

#if SPI_METHOD == SPI_METHOD_IRQ
spiSend(SPI_DRIVER, 1, &data);
#elif SPI_METHOD == SPI_METHOD_POLLING
spiPolledExchange(SPI_DRIVER, data);
#endif

spiUnselect(&SPID2);
spiStop(&SPID2);
release_bus(g);

palTogglePad(GPIOD, GPIOD_DEBUG_LED); /* Orange. */

}

I get following: DEBUG_LED (light green) indicates wite_data() execution:

Posted

I took a quick look at UC1701v2.zip from one of your earlier posts.

gdisp_lld_draw_pixel() is definitely something you want to be using. The reason why you don't see write_cmd() and write_data() being called from the application code is because your display driver code is accessing a framebuffer in the drawing routines (through the RAM() macro) and not directly talking to the display each time it is performing a drawing operation. Did you check whether the framebuffer content is ever being flushed? It looks like you implemented the function but turned it of in the configuration.

I don't have time to look at the UC1701 datasheet this week but the comment "This controller doesn't require flushing" next to the flushing setting in the configuration file seems a bit strange when looking at the rest of the driver code which always just accesses the framebuffer in the drivers private area (GDisplay->priv).

~ Tectu

Posted

Hello Tectu,

thank you for your response.

Should I write my own code intead of the RAM stuff inside GDISP_HARDWARE_DRAWPIXEL? I will replace the the following code:

		if (gdispColor2Native(g->p.color) != gdispColor2Native(Black))
RAM(g)[xyaddr(x, y)] |= xybit(y);
else
RAM(g)[xyaddr(x, y)] &= ~xybit(y);
g->flags |= GDISP_FLG_NEEDFLUSH;

But I dont know how. I know the command to set the row, page address and writing data. What's the best way to implement this. Is there a driver which implements this? Should I implement my own drawString()? My main.c looks now like this:

#include "ch.h"
#include "hal.h"
#include "test.h"
#include "gfx.h"

/*
* This is a periodic thread that does absolutely nothing except flashing
* a LED.
*/
static THD_WORKING_AREA(waThread1, 128);
static THD_FUNCTION(Thread1, arg)
{
(void) arg;

chRegSetThreadName("blinker");

while (true) {
// palTogglePad(GPIOD, GPIOD_DEBUG_LED); /* Orange. */
// chThdSleepMilliseconds(500);
}
}

int main(void)
{

coord_t width, height;
coord_t i, j;

halInit();
chSysInit();
gfxInit();

gdispClear(Black);
gdispFillArea(0, 0, 20, 20, White);

font_t fontUI2 = gdispOpenFont("UI2*");
gdispDrawString(10,10,"Hi my lovely ugfx",fontUI2,Black);

chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);

// Get the screen size
width = gdispGetWidth();
height = gdispGetHeight();

// Code Here
gdispDrawBox(10, 10, width/2, height/2, Black);
gdispFillArea(width/2, height/2, width/2-10, height/2-10, Black);
gdispDrawLine(5, 30, width-50, height-40, White);

for(i = 5, j = 0; i < width && j < height; i += 7, j += i/20)
gdispDrawPixel(i, j, Black);

while(TRUE) {
gfxSleepMilliseconds(500);
}
}

I think UC1701 doesn't support either GDISP_HARDWARE_DRAW_PIXEL or GDISP_HARDWARE_STREAM_WRITE.

Posted

Now I replaced code in gdisp.c like following:

	// Worst is pixel drawing
#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
// if (gvmt(g)->pixel)
//#endif
{
coord_t x0, y0, x1, y1;

x0 = g->p.x;
y0 = g->p.y;
x1 = g->p.x + g->p.cx;
y1 = g->p.y + g->p.cy;

for(; g->p.y < y1; g->p.y++, g->p.x = x0)
for(; g->p.x < x1; g->p.x++)
gdisp_lld_draw_pixel(g);
g->p.y = y0;

for(; g->p.y < y1; g->p.y++, g->p.x = x0){
//Set page address
write_cmd(g,0xB0+g->p.y);
for(; g->p.x < x1; g->p.x++){
//Set column address
write_cmd(g,g->p.x&0x0F); //LSB address
write_cmd(g,0x10+(g->p.x>>4)); //MSB address
gdisp_lld_draw_pixel(g);
}
}
g->p.y = y0;
return;
}
#endif

Means I wrote inside a private space, that is reserved for ugfx, to set column and page addresses:

		for(; g->p.y < y1; g->p.y++, g->p.x = x0){
//Set page address
write_cmd(g,0xB0+g->p.y);
for(; g->p.x < x1; g->p.x++){
//Set column address
write_cmd(g,g->p.x&0x0F); //LSB address
write_cmd(g,0x10+(g->p.x>>4)); //MSB address
gdisp_lld_draw_pixel(g);
}
}

I replaced also the code inside GDISP_HARDWARE_DRAWPIXEL like following:

#if GDISP_HARDWARE_DRAWPIXEL
LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
if(g->p.color == Black){
// Write all pixels
write_data(g,1);
}else {
// Delete all pixels
write_data(g,0);
}
}
#endif

My main.c:

#include "ch.h"
#include "hal.h"
#include "test.h"
#include "gfx.h"

/*
* This is a periodic thread that does absolutely nothing except flashing
* a LED.
*/
static THD_WORKING_AREA(waThread1, 128);
static THD_FUNCTION(Thread1, arg)
{
(void) arg;

chRegSetThreadName("blinker");

while (true) {
palTogglePad(GPIOD, GPIOD_DEBUG_LED); /* Orange. */
chThdSleepMilliseconds(500);
}
}

int main(void)
{

// coord_t width, height;
// coord_t i, j;

halInit();
chSysInit();
gfxInit();

gdispClear(Black);
gdispFillArea(0, 0, 20, 20, White);


while(TRUE) {
gfxSleepMilliseconds(500);
}
}

My board file:

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

/**
* @file boards/addons/gdisp/board_UC1701_spi.h
* @brief GDISP Graphic Driver subsystem board interface for the UC1701 display.
*
* @note This file contains a mix of hardware specific and operating system specific
* code. You will need to change it for your CPU and/or operating system.
*/



#ifndef _GDISP_LLD_BOARD_H
#define _GDISP_LLD_BOARD_H


//-------------------
// Pin & SPI setup
#define SPI_METHOD_IRQ 1
#define SPI_METHOD_POLLING 2
#define SPI_METHOD SPI_METHOD_POLLING
// SPI1
#define SPI_DRIVER (&SPID2)
#define SPI_PORT GPIOB
#define SCK_PAD GPIOB_LCD_SCK //PA5
#define MOSI_PAD GPIOB_LCD_MOSI

#define CS_PORT GPIOB
#define RESET_PORT GPIOB
#define DNC_PORT GPIOB
#define CS_PAD GPIOB_LCD_CSB
#define RESET_PAD GPIOB_LCD_RESET
#define DNC_PAD GPIOB_LCD_RS
#define SET_RST palSetPad(GPIOB,GPIOB_LCD_RESET );
#define CLR_RST palClearPad(GPIOB,GPIOB_LCD_RESET);


// 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_128 //AJUST SPEED HERE..
};

//----------------
static inline void init_board(GDisplay *g) {
/*
* SPI2 I/O pins setup.
*/
palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(5) |
PAL_STM32_OSPEED_HIGHEST); /* New SCK. */
palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(5) |
PAL_STM32_OSPEED_HIGHEST); /* New MOSI. */
palSetPadMode(GPIOB, 12, PAL_MODE_OUTPUT_PUSHPULL |
PAL_STM32_OSPEED_HIGHEST); /* New CS. */
palSetPad(GPIOB, 12);
}

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

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

static inline void acquire_bus(GDisplay *g) {
(void) g;
spiAcquireBus(&SPID2);
}

static inline void release_bus(GDisplay *g) {
(void) g;
spiReleaseBus(&SPID2);
}

static inline void write_cmd(GDisplay *g, uint8_t cmd) {
uint8_t command[1];
(void) g;

palClearPad(GPIOB, GPIOB_LCD_RS); /* Clear RS to write cmd. */

command[0] = cmd;

spiStart(&SPID2, &spi_cfg);
spiSelect(&SPID2);
gfxSleepMicroseconds(1); // according
spiSend(&SPID2, 1, command);
spiUnselect(&SPID2);
spiStop(&SPID2);

}

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

acquire_bus(g);
palSetPad(GPIOB, GPIOB_LCD_RS); /* Set RS to write data. */
spiStart(&SPID2, &spi_cfg);
spiSelect(&SPID2);
gfxSleepMicroseconds(1);

#if SPI_METHOD == SPI_METHOD_IRQ
spiSend(SPI_DRIVER, 1, &data);
#elif SPI_METHOD == SPI_METHOD_POLLING
spiPolledExchange(SPI_DRIVER, data);
#endif

spiUnselect(&SPID2);
spiStop(&SPID2);
release_bus(g);
}

#endif /* _GDISP_LLD_BOARD_H */

But no success

Posted

Replacing code in gdisp.c is a big no no. That code is complicated and interrelated. It is driven by the defines in config file in your driver.

As I have not looked at your driver controller data sheet, can you tell me about it. Is it monochrome or color, the number of bits per pixel supported, is it a window stream or pixel controller (as per the wiki), does the controller use a dual port ram framebuffer or is the display framebuffer accessible via controller commands?

Generally only monochrome controllers and dual port framebuffer should be implemented using a driver using a framebuffer.

Monochrome displays require flushing (in the driver config file) but dual port framebuffer typically don't.

Look particularly closely at drivers for controllers that are similar in nature to yours.

Posted
Replacing code in gdisp.c is a big no no.
Means a big yes ;)
That code is complicated and interrelated. It is driven by the defines in config file in your driver.

As I have not looked at your driver controller data sheet, can you tell me about it. Is it monochrome or color, the number of bits per pixel supported, is it a window stream or pixel controller (as per the wiki), does the controller use a dual port ram framebuffer or is the display framebuffer accessible via controller commands?

It's a monochrome, 8 bits per pixel controller. The Display Data RAM (could be a frame buffer) is accessible via controller commands. "If CD=0, the data byte will be decoded as command. If CD=1, this 8-bit will be treated as data and transferred to proper address in the Display Data RAM on the rising edge of the last SCK pulse."[http://www.lcd-module.de/eng/pdf/zubehoer/uc1701.pdf, Page 26]

Generally only monochrome controllers and dual port framebuffer should be implemented using a driver using a framebuffer.

Monochrome displays require flushing (in the driver config file) but dual port framebuffer typically don't.

Despite UC1701 doesn't have a flushing mechanism, only DISPLAY DATA LATCHES, should I activate GDISP_NEED_AUTOFLUSH?

Look particularly closely at drivers for controllers that are similar in nature to yours.

Posted

When you say "8 bits per pixel" I assume you mean 8 pixels per byte.

As a monochrome display you will need a framebuffer and flushing will need to be turned on in your config file.

GDISP_NEED_AUTOFLUSH is the correct setting to set to TRUE in your driver config file.

With that setting turned on the GDISP system makes sure that your driver flush function gets called automatically as needed.

Your flush function then needs to transfer the contents of the framebuffer to the controller.

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