Jump to content

Mikromedia Plus for STM32


lliypuk

Recommended Posts

Unfortunately other things have intervened and I have not completed support for this board yet. I will get back to it and try and get it done over the next week or so.

From memory the drivers are largely supported but the board is not yet supported in chibios. It was the chibios specific stuff that was taking the time.

Link to comment
Share on other sites

Ok so I made a zip with what I hope is relevant info.

Inside you will find chibios board files, a mcuconf with settings that are pretty much what they are in the Mikromedia compiler settings. Everything works with chibios as far as I tried anyways.

I know that Ethernet works,

USB works although chibios keeps complaining about usb clock not being exactly 48 MHz but it should work fine with 50 I think. I commented out the error check for that in OTGv1 driver (usb_lld.h) somewhere around line 183


#if STM32_USBCLK != 48000000
//#error "the USB OTG driver requires a 48MHz clock"
#endif

Although I think a better option would be to check for board ID to make sort of an exception for this board since its wired a** backwards :lol:

So anyways inside the zip there is display driver (slightly modified original that I found in your repo), touch panel driver (so far works fine, but I didn't have a chance to experiment much).

Also there is an annoying issue with the PWM of the backlight syncing weirdly with lcd refresh so it flickers randomly. I tweaked the LCD_Parameters in particular set the refresh to 73FPS to minimize the effect. I tried to change PWM frequency, use DBC and front/back porches and widths to no avail.

Hopefully its useful to you guys :)

Cheers

MikromediaPlus-STM32-M4.zip

Link to comment
Share on other sites

Hey, no worries :) that's actually my first ever contribution to open source community. I'm currently trying to work out a DMA solution to this. Maybe pwm triggered I'm not sure. Kind of new to DMA stuff. I'm thinking something like 2 DMA streams one for lower byte and one for higher and have them trigger write to gpio port every time the WR pin is high so display can read when WR goes low.

Link to comment
Share on other sites

Dma is likely to be slower than gpio bit banging although it will use less cpu.

If you want best update speed don't use dma. If you want lowest cpu load then use dma.

Dma is really also only of value for large writes as there is extra overhead in setting up the dma. Occasional writes are also better than continuous writes with dma as if the dma is busy when you come back to write more the cpu ends up busy waiting for it anyway.

For these reasons dma is often not the advantage it would at first appear.

A situation where dma would be very useful is in video display. The writes are occasional (one write per frame), they are large (the full display area) and the cpu can make use of the extra time in decoding the next frame.

Link to comment
Share on other sites

I see, thanks for the info. This backlight flickering is driving me crazy tho. I can't figure out how to make it stop. Even using the same init parameters like in mikroC library still makes it flicker. But if you upload a program written in mikroC compiler its not as bad.

Link to comment
Share on other sites

I will look at it in the next few days. The stm32429-idiscovery board has the same problem based on the symptoms you describe. It is time I got to the bottom of it.

I suspect the problem is not purely the back light but rather the way halftone colors are multiplexed on the display.

It is interesting to note that the demos supplied by the manufacturers tend to use mostly saturated colors. I suspect that this is an attempt to hide a flaw in this type of controller or display. I will know more when I get time to do some more debugging.

PS. The Mikromedia STM32 board (without the plus) does not have this problem but it uses a different controller chip. The change in controller chip for that board occurred sometime after the initial release so perhaps it was to fix to related the same problem

Link to comment
Share on other sites

I'm going to test the pwm coming from the ssd1963 later with a scope see if something is wrong there. But if you look at the board file for the Embest lcd pwm generated there is 200Hz and it doesn't seem to be a problem. The only real difference is that pwm is generated by STM and not the lcd controller (I do realize that it is a different controller chip). Maybe pwm generated by ssd1963 is unstable or something or frequency is off or duty cycle unstable :?

Link to comment
Share on other sites

I'm going to test the pwm coming from the ssd1963 later with a scope see if something is wrong there. But if you look at the board file for the Embest lcd pwm generated there is 200Hz and it doesn't seem to be a problem. The only real difference is that pwm is generated by STM and not the lcd controller (I do realize that it is a different controller chip). Maybe pwm generated by ssd1963 is unstable or something or frequency is off or duty cycle unstable :?

I'm using a display (displaytech INT070ATFT.pdf) where the backlight is controlled by PWM from the SSD1963, and that's well behaved and fully controllable. So maybe its a hardware issue.

Link to comment
Share on other sites

Alright no more flickering. I basically just plugged in the values directly from the MikroC library file bypassing all the calculations in the driver and the display is behaving properly now. I am going to try and trace where the problem was exactly. It is definitely issue with incorrect vsync pulse, porches and etc. The Mikromedia board uses some kind of cheap I guess display. It is almost impossible if not actually impossible to find a correct datasheet for it. I have maybe 5 already all from different manufacturers. I will try to derive correct values from MicroC code since it is working correctly now.

I'm using a display (displaytech INT070ATFT.pdf) where the backlight is controlled by PWM from the SSD1963, and that's well behaved and fully controllable. So maybe its a hardware issue.

I was starting to get worried that it was but it turned out the hardware is ok... phew :)

Link to comment
Share on other sites

Ok so I finally traced the issue to this line of code.


/* Tear effect indicator ON. This is used to tell the host MCU when the driver is not refreshing the panel (during front/back porch) */
write_reg(g, SSD1963_SET_TEAR_ON, 0x00);

If you comment this out the flickering problem disappears.

So I guess this feature should not be used unless utilized by host processor?

Anyways hopefully this helps someone someday.

Link to comment
Share on other sites

I stumbled upon another issue. For some reason when you activate usb OTG driver to have console over serial the MCU goes into sysHalt handler with reason "i2cMasterTransmitTimeout". I am not sure what exactly is going on, but I'll test later on my Embest board and see if its issue with MikromediaPlus board or not. I already triple checked the mouse driver and the init for it, set timeouts to TIME_INFINITE and some random values but nothing changed. Tried setting usb thread stack size to larger etc. The problem happens only when I start the shell thread. If I don't create shell thread everything works as expected. The issue seems to appear only when using touch and OTG together. If you only displaying console to the lcd without requiring input from touch it works fine. I think I'll try to use I2C and OTG together without uGFX to see if these two cannot play well together.

EDIT: This is now fixed and working properly for now anyways. Turns out in the example of using CDC-OTG you use SDU along with serial driver. If you only use usb-otg without serial it works properly.

Link to comment
Share on other sites

I finally got an opportunity to try the Mikromedia-Plus-STM32-M4 code.

I have added the code now to the master repository (with changes).

I have some interesting results:

  • The display code that you had wouldn't work for me. There was simply no display at all. Reverting to the standard SSD1963 code worked for me and I had none of the flicker issues that you had. It was rock-solid. I have tried to integrate your code as much as possible whilst still maintaining a working driver. You will see I have defined SSD1963_INIT_METHOD_2. If set in the board file it will use your code (with some mods). Without it, it uses mostly the old code.
  • I have not tried other orientations, changing the backlight level or contrast although I fixed a couple of obvious problems. I will write a test utility specifically for this so that all the drivers can have these functions more easily checked.
  • The touch driver is not working correctly in self-calibration mode. I will need to do more work with this.
  • I have not tried the ugfx audio on this board yet.
  • I have not tried any other hardware (non-ugfx related eg Ethernet, sdcard) yet.
  • My board is labelled V1.02 (just below the SD-Card and above the 2.4G transceiver.

Can you please try the latest repository code and let me know how you go. I am particularly interested in any changes you have subsequently made to your source, any changes to the ChibiOS files and how the display driver works for you.

Please also let me know what hardware revision your board is.

Thank-you for your great help.

Link to comment
Share on other sites

My board is the same revision like yours. I have modified the driver a little more since I sent you the files. I no longer use DBC as I figured that my flickering issues were not caused by that. As for the rest it is pretty much what the datasheet says it is supposed to be. The whole init sequence is taken from the MicroC library code. That is very strange that it didn't work for your board. Let me give you the latest driver I have so you can compare. I will attach it to this post in a bit.


static inline void set_backlight(GDisplay *g, uint8_t percent) {
// The SSD1963 has a built-in PWM (duty_cycle 00..FF).
// Its output can be used by a Dynamic Background Control or by a host (user)
// Check your LCD's hardware, the PWM connection is default left open and instead
// connected to a LED connection on the breakout board

write_index(g, SSD1963_SET_PWM_CONF); //set PWM for BackLight
write_data(g, 0x06);
// write_data(g, 0x0E); // PWMF[7] = 2, PWM base freq = PLL/(256*(1+5))/256 = 300Hz for a PLL freq = 120MHz (source: Displaytech)
if (percent == 0xFF) // use percent==0xFF to turn off SSD1963 pwm in power SLEEP or DEEP SLEEP mode
write_data(g, 0x00);
else if (percent >= 100) // Fully on for any percentage >= 100
write_data(g, 0xFF);
else
write_data(g, (percent*255)/100 & 0x00FF);// Set brightness percentage.
write_data(g, 0x01); // PWM enable control by host (not DBC)
write_data(g, 0xFF); // DBC manual brightness
write_data(g, 0x00); // DBC minimum brightness
write_data(g, 0x01); // Brightness prescaler when Transition effect enabled
}

/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/

LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
LCD_Parameters * lcdp;

/*
* Some displays (e.g. Displaytech) have an on-board setup process which just requires that we don't touch anything for a time after power up.
* For this type of display define GDISP_SSD1963_NO_INIT as TRUE, and implement an appropriate delay in the board file.
* With such displays we can skip most of the initialisation. We also skip pulsing the reset pin, since it
* will introduce an extra second or so of display to the startup time.
*/

// The private area for this controller is the LCD timings
lcdp = (void *)&DisplayTimings[g->controllerdisplay];
g->priv = lcdp;

// Initialise the board interface
init_board(g);

#if !GDISP_SSD1963_NO_INIT
// Hardware reset
setpin_reset(g, TRUE);
gfxSleepMilliseconds(200);
setpin_reset(g, FALSE);
gfxSleepMilliseconds(200);
#endif

// Get the bus for the following initialisation commands
acquire_bus(g);

#if !GDISP_SSD1963_NO_INIT
write_index(g, SSD1963_SOFT_RESET); // Software reset - clears almost everything (apart from PLL)
write_index(g, SSD1963_SOFT_RESET); // Software reset - clears almost everything (apart from PLL)
write_index(g, SSD1963_SOFT_RESET); // Software reset - clears almost everything (apart from PLL)

/* Driver PLL config */
write_index(g, SSD1963_SET_PLL_MN);
write_data(g, 35); // PLLclk = REFclk (10Mhz) * 36 (360Mhz)
write_data(g, 2); // SYSclk = PLLclk / 3 (120MHz)
write_data(g, 0x54); // Apply calculation bit, else it is ignored
write_reg(g, SSD1963_SET_PLL, 0x01); // Enable PLL
gfxSleepMicroseconds(100); // Let PLL stabilize
write_reg(g, SSD1963_SET_PLL, 0x03); // Use PLL

/* LCD panel parameters */
write_index(g, SSD1963_SET_GDISP_MODE);
write_data(g, lcdp->flags & 0xFF);
write_data(g, (lcdp->flags >> 8) & 0xFF);
//** write_data(g, 0x18); //Enabled dithering
//** write_data(g, 0x00);
write_data16(g, lcdp->width-1);
write_data16(g, lcdp->height-1);
write_data(g, 0x00); // RGB - line sequences for serial TFT
#endif

// From Displaytech example - for larger horizontal resolutions - not sure if display-specific
if (lcdp->width >= 640)
write_reg(g, SSD1963_SET_ADDRESS_MODE, 2); // Flip horizontal direction

write_reg(g, SSD1963_SET_PIXEL_DATA_INTERFACE, SSD1963_PDI_16BIT565);
write_reg(g, SSD1963_SET_PIXEL_FORMAT, 0x50);

#if !GDISP_SSD1963_NO_INIT
/* LCD Clock specs */
write_index(g, SSD1963_SET_LSHIFT_FREQ);
write_data(g, (lcdp->fpr >> 16) & 0xFF);
write_data(g, (lcdp->fpr >> 8) & 0xFF);
write_data(g, lcdp->fpr & 0xFF);

write_index(g, SSD1963_SET_HORI_PERIOD);
write_data16(g, lcdp->hperiod); // According to datasheet this
write_data16(g, lcdp->hpulse + lcdp->hbporch);
write_data(g, lcdp->hpulse - 1); // and this should be (value - 1) but in MicroC this is how it is
write_data(g, 0x00);
write_data(g, 0x00);
write_data(g, 0x00);


write_index(g, SSD1963_SET_VERT_PERIOD);
write_data16(g, lcdp->vperiod - 1); // According to datasheet this
write_data16(g, lcdp->vpulse + lcdp->vbporch);
write_data(g, lcdp->vpulse - 1); // and this should be (value - 1) but in MicroC this is how it is
write_data(g, 0x00);
write_data(g, 0x00);
#endif

/* Tear effect indicator ON. This is used to tell the host MCU when the driver is not refreshing the panel (during front/back porch) */
//write_reg(g, SSD1963_SET_TEAR_ON, 0x00);

/* Turn on */
write_index(g, SSD1963_SET_DISPLAY_ON);

/* Turn on the back-light */
set_backlight(g, GDISP_INITIAL_BACKLIGHT);

// Finish Init
post_init_board(g);

// Release the bus
release_bus(g);

/* Initialise the GDISP structure */
g->g.Width = lcdp->width;
g->g.Height = lcdp->height;
g->g.Orientation = GDISP_ROTATE_0;
g->g.Powermode = powerOn;
g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
g->g.Contrast = GDISP_INITIAL_CONTRAST;
return TRUE;
}

And the board code:


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

static const LCD_Parameters DisplayTimings[] = {
// You need one of these array elements per display
{
480, 272, // Panel width and height
2, 2, 41, // Horizontal Timings (back porch, front porch, pulse)
CALC_PERIOD(480,2,2,41), // Total Horizontal Period (calculated from above line)
2, 2, 10, // Vertical Timings (back porch, front porch, pulse)
CALC_PERIOD(272,2,2,10), // Total Vertical Period (calculated from above line)
CALC_FPR(480,272,2,2,41,2,2,10,60ULL), // FPR - the 60ULL is the frames per second. Note the ULL! 83271,
LCD_PANEL_DATA_WIDTH_24BIT | LCD_PANEL_ENABLE_DITHERING
},
};

/* GPIO Pin Config */
#define GDISP_CMD_PORT GPIOF
#define GDISP_DATA_LO_PORT GPIOG
#define GDISP_DATA_HI_PORT GPIOE

#define GDISP_WR 11
#define GDISP_RD 12
#define GDISP_CS 13
#define GDISP_RST 14
#define GDISP_DC 15

#define SET_CS palSetPad(GDISP_CMD_PORT, GDISP_CS);
#define CLR_CS palClearPad(GDISP_CMD_PORT, GDISP_CS);
#define SET_RST palSetPad(GDISP_CMD_PORT, GDISP_RST);
#define CLR_RST palClearPad(GDISP_CMD_PORT, GDISP_RST);
#define SET_WR palSetPad(GDISP_CMD_PORT, GDISP_WR);
#define CLR_WR palClearPad(GDISP_CMD_PORT, GDISP_WR);
#define SET_RD palSetPad(GDISP_CMD_PORT, GDISP_RD);
#define CLR_RD palClearPad(GDISP_CMD_PORT, GDISP_RD);
#define SET_DC palSetPad(GDISP_CMD_PORT, GDISP_DC);
#define CLR_DC palClearPad(GDISP_CMD_PORT, GDISP_DC);

#define writeStrobe { CLR_WR; asm volatile ("nop;"); SET_WR; }

IOBus busCMD = { GDISP_CMD_PORT, (1 << GDISP_CS) | (1 << GDISP_RST) | (1 << GDISP_WR) | (1 << GDISP_RD) | (1 << GDISP_DC), 11 };
IOBus busDataLo = { GDISP_DATA_LO_PORT, 0xFF, 0 };
IOBus busDataHi = { GDISP_DATA_HI_PORT, 0xFF, 8 };


static inline void init_board(GDisplay *g) {
g->board = 0;
switch(g->controllerdisplay) {
case 0:
{
palSetBusMode(&busCMD, PAL_MODE_OUTPUT_PUSHPULL);
palSetBusMode(&busDataLo, PAL_MODE_OUTPUT_PUSHPULL);
palSetBusMode(&busDataHi, PAL_MODE_OUTPUT_PUSHPULL);
SET_CS; SET_WR; SET_RD; SET_DC; SET_RST;
break;
}
default:
break;
}
}

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

static inline void setpin_reset(GDisplay *g, bool_t state) {
(void) g;
if (state) {
CLR_RST;
} else {
SET_RST;
}
}

static inline void acquire_bus(GDisplay *g) {
(void) g;
CLR_CS;
}

static inline void release_bus(GDisplay *g) {
(void) g;
SET_CS;
}

static inline void write_index(GDisplay *g, uint16_t index) {
(void) g;

CLR_DC;
palWriteBus(&busDataLo, (index & 0xFF));
palWriteBus(&busDataHi, (index >> 8));
writeStrobe;
SET_DC;
}

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

palWriteBus(&busDataLo, (data & 0xFF));
palWriteBus(&busDataHi, (data >> 8));
writeStrobe;
}

static inline void setreadmode(GDisplay *g) {
(void) g;
palSetBusMode(&busDataLo, PAL_MODE_OUTPUT_PUSHPULL);
palSetBusMode(&busDataHi, PAL_MODE_OUTPUT_PUSHPULL);
}

static inline void setwritemode(GDisplay *g) {
(void) g;
palSetBusMode(&busDataLo, PAL_MODE_INPUT_PULLUP);
palSetBusMode(&busDataHi, PAL_MODE_INPUT_PULLUP);
}

static inline uint16_t read_data(GDisplay *g) {
(void) g;

uint16_t data;
CLR_RD;
data = (palReadBus(&busDataHi) << 8) | palReadBus(&busDataLo);
SET_RD;
return data;
}

#endif /* _GDISP_LLD_BOARD_H */

PS: If you set your PWM Frequency at 0x01 then PWM Freq = 120Mhz / (256 * 1) / 256 = 1831 Hz which is way beyond the TPS61041 EN pin input PWM signal. According to it's datasheet the PWM it can accept is 100Hz - 500Hz.

So value of 0x06 makes more sense which would put your PWM freq at 120Mhz / (256 * 6) / 256 = 305 Hz. That is of course given that your PLL clock is actually set at 120Mhz.

Link to comment
Share on other sites

[*] I have not tried the ugfx audio on this board yet.

[*] I have not tried any other hardware (non-ugfx related eg Ethernet, sdcard) yet.

I'm actually trying to use audio on this board I will report if its working when I get a chance to finish.

From what I tried on this board:

[*] Ethernet is working provided you use same clock settings like MicroC compiler. (mcuconf.h is included in the attachment I posted on the first page)

checked with lwip (UDP and TCP) working well.

[*] USB-CDC is working provided you comment out USB clock check in chibios source in OTGv1 usb_lld.h around line 182.

Also don't use serial driver along with SDU driver and touch input driver or your system will lock up with i2cMasterTransmitTimeout reason. Not sure why.

[*] GFILE with FatFS working fine with sdcard provided you set your pins correctly in chibios board file (Data and CMD pins with pullups and SCK pin floating works correctly for me). Also add code to check if card is inserted in your board.c file. In case of Mikromedia Plus board it is just:


bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
(void)sdcp;
return !palReadPad(GPIOD, GPIOD_SD_CD);
}

I was able to read and write and get directory listing.

One thing to note tho, if you want to load and save your touch calibration to sdcard you have to disable OS init from GFX (GFX_NO_OS_INIT set to TRUE in gfxconf.h) and then do in your main function:


halInit();
chSysInit();

sdcStart(&SDCD1, &sdcconf);
sdcConnect(&SDCD1);

gfxInit();

Unless there is another way this is what worked for me.

[*] I am writing a driver so to speak to use the built in flash module with fatfs. Although I am not sure how useful it would be to people but I would like to have it. The only thing that bothers me is that it is Block erase size is 512Kb which zaps a huge portion of flash for no reason if you only updating a small amount of information. (now I'm not a pro in flash memory but I don't think this is good :) ). Also I am thinking to swap it for Atmel flash module because it provides 4k, 16k and 32k erase block options if the pinout would be compatible, I havent checked yet.

EDIT: Never mind about the flash I am an idiot :D messed up Mbit and Mbyte but still programming 64-kbyte block is no good. And I just figured out that the board actually hosts a F80-100HIP chip (EN25F80) flash which allows individual 4-kbyte sectors to be erased instead of 64-kbyte blocks so all good here :)

Link to comment
Share on other sites

No reason that I know of.

There is simply nothing that we should be able to do to cause that given we avoid any interrupt level code in uGFX.

The only thing I can think of that might be application related is that maybe one of your stacks are too small in the linker script you are using (either your main stack or your interrupt stack).

Another possibility is that you are calling the FAT operations in multiple threads and they are overlapping. The FAT library code definitely does not support multiple threads making simultaneous requests and I don't think we have added any threading protection in GFILE either unlike GDISP which is fully protected from re-entrancy (if you specify GDISP_NEED_MULTITHREAD) and GWIN (by default).

Link to comment
Share on other sites

I have updated some of your changes back into the master repository. A few things to check...

  • Can you please check that the pin set up's are correct in the ChibiOS_Board file in the master repository to allow the SD-Card to work. I have run out of time to test it myself this weekend.
  • I have added the sdio pin check from your code into that board file.
  • In your board file - you have the direction's swapped in the setreadmode() and setwritemode() routines. This will only be a problem if you put the display into low power mode.
  • I have raised the refresh rate back to 73Hz. 60Hz created noticeable flicker for me when lights are on. I guess this is a frequency difference effect with the mains light (I am in Australia which has 50Hz mains).
  • This display seems extremely slow. I can see it filling the screen eg change the color scheme in the widget demo. This is surprising given that it is a parrellel interface. Compared to the Mikromedia-STM32-M4 board (non-plus) which should be very similar and several other boards which use SPI interfaces (which should be much slower) this display is a LOT slower. I am not sure if it by nature of the display controller, an issue with the CPU running much slower than what it should, or some other problem. Can you please look at it and see what you can find.
  • In light of the above I have removed the delay in the write-strobe in the board file. This still works and seems to help with the speed a little. It might need to be reversed if you find the problem was perhaps CPU configuration related.

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