hekthe Posted August 13, 2015 Report Posted August 13, 2015 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
Joel Bodenmann Posted August 13, 2015 Report Posted August 13, 2015 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_ModelPlease 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_FileYour 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=249To 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
hekthe Posted August 15, 2015 Author Report Posted August 15, 2015 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 byeEADOGS102.zip
hekthe Posted August 15, 2015 Author Report Posted August 15, 2015 Hello Tectu,thanks a lot for your help (through IRC chat). Here my update. Now the driver is named correctly UC1701. Because UC1701 is the actual display controller.Bye bye~ hektheUC1701.zip
hekthe Posted August 16, 2015 Author Report Posted August 16, 2015 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
hekthe Posted August 16, 2015 Author Report Posted August 16, 2015 Attached LA screenshots with init commands on SPI with a 10 Mhz sample rate.CommandDataOnSPIScreenShots.zip
hekthe Posted August 16, 2015 Author Report Posted August 16, 2015 (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 August 16, 2015 by Guest
Joel Bodenmann Posted August 16, 2015 Report Posted August 16, 2015 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
hekthe Posted August 16, 2015 Author Report Posted August 16, 2015 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:
Joel Bodenmann Posted August 17, 2015 Report Posted August 17, 2015 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
hekthe Posted August 18, 2015 Author Report Posted August 18, 2015 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.
hekthe Posted August 20, 2015 Author Report Posted August 20, 2015 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; } #endifMeans 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); } }#endifMy 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 KHzstatic 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
inmarket Posted August 20, 2015 Report Posted August 20, 2015 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.
hekthe Posted August 21, 2015 Author Report Posted August 21, 2015 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.
inmarket Posted August 21, 2015 Report Posted August 21, 2015 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.
hekthe Posted August 21, 2015 Author Report Posted August 21, 2015 Is http://forum.ugfx.org/viewtopic.php?f=22&t=192&p=1486&hilit=framebuffer#p1486 interesting for me? Can I use this to write my flush function? I searched for a flush function example but didn't find.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now