OpenSourceEBike / Color_LCD

21 stars 9 forks source link

Some 850Cs apparently show a white screen when running our software #9

Closed geeksville closed 4 years ago

geeksville commented 5 years ago

And when installing the factory software the X direction is reversed.

Moving gitter discussion here because I want to keep persistent notes on the investigation.

geeksville commented 5 years ago

ok looking now @casainho for the values in ugui_bafang_850.c such as: lcd_write_command(0xD0); // Power Setting lcd_write_data_8bits(0x07); lcd_write_data_8bits(0x41); lcd_write_data_8bits(0x1D);

lcd_write_command(0xD2); // Power_Setting for Normal Mode lcd_write_data_8bits(0x01); lcd_write_data_8bits(0x11);

lcd_write_command(0xC0); // Panel Driving Setting lcd_write_data_8bits(0x10); lcd_write_data_8bits(0x3B); lcd_write_data_8bits(0x00); lcd_write_data_8bits(0x02); lcd_write_data_8bits(0x11);

did you get those from the ugui sample code or did you capture them by watching to see what the factory firmware was doing? I'm currently reading the ssd 1963 datasheet and I bet the white screen problem is either a) the init cmds we are sending are not quite right (will know more after I read me) or b) lcd_write_command() (and similar routines) isn't obeying the hold time required for the assertion of WR (and this ugui based example code is on the hairy edge of working on all 850Cs, and some are more lucky than others). If the answer turns out to be a) I'll try to find what the right init is (and figure out how to make the problem show up on my good 850C before fixing it). If the answer turns out to be b. I'll try to make the problem worse on my 850C then make the timing tighter.

geeksville commented 5 years ago

Update: Problem is definitely not option b, according to the ssd1963 datasheet and the disassembly the hold time on the WR signal is fine.

But option a is looking super plausible. The init code in ugui_bafang_850C register writes don't match what the datasheet says many of those registers are. Comments here: https://github.com/geeksville/Color_LCD/commit/88ccb0242d058dcdb8db67e0546ae44069422a10

The comment at the head of this file says that Achim wrote this for a SSD1963, but a fair bit of the init is just wrong. Possibly he did it without access to the datasheet (and was instead reverse engineering)? @casainho any chance you've looked at the LCD board and seen the part number to confirm it is a SSD1963 we are using and not a similar chip?

I'm experimenting now with doing the init recommended in the datasheet.

geeksville commented 5 years ago

Ok yeah - I thats the problem. I found this part which seems to be identical to the one on the 850C:

https://www.aliexpress.com/item/32313662714.html?spm=a2g0o.productlist.0.0.53f01cdboqrKwx&algo_pvid=25991649-e239-4fa8-8530-b3efc12716ad&algo_expid=25991649-e239-4fa8-8530-b3efc12716ad-2&btsid=f6cb09df-f8fd-4e73-ad4d-5a28e95f5b62&ws_ab_test=searchweb0_0,searchweb201602_1,searchweb201603_60

I've copied the pinout jpg into our repo. The controller is a ILI9481, and the init is quite similar to what the ugui guy provided in his example code, but it is not the same. Changing the init code to be more ILI9481ish and testing now.

casainho commented 5 years ago

One user reported that he could halt the cpu at startup and he could see the image inverted but after running, it would turn full white. I wonder if the init is ok but something after is failing.

I did hookup the logic analyzer to get the full init commands. That are the commands for the init of my display version.

geeksville commented 5 years ago

ah! that explains why the init commands don't match the comment saying the code was for a SSD1963. Ok - I'll take a look tomorrow (comparing the values you captured with the LA to the datasheet)

r0mko commented 4 years ago

Keeping fingers crossed. Thanks a lot for your efforts! Unfortunately I don't have any STM32 debugging rig and all I can is just wait for a solution.

geeksville commented 4 years ago

ok - I think I have a plausible fix. testing now, will add update to bug in a few hrs.

geeksville commented 4 years ago

Ok,

I just spent a fair amount of time reading the datasheet for the ILI9481 and looking at the existing init code. Some findings.

I've checked in my changes into our dev branch. @casainho could you build a bin for @r0mko to try? I think it has a pretty good shot of working - alas, I haven't been able to fuzz stuff enough to somehow make my display fail. I would build it myself but I don't really know how you are using USE_WITH_BOOTLOADER for end-user builds of the 850C code (I've never tried installing an end user build and have been meaning to add a bootloader to my board).

If this fixes the whitescreen, I bet the fix for the left right swapping is ... ( see https://github.com/OpenSource-EBike-firmware/Color_LCD/issues/10 )

r0mko commented 4 years ago

Hi @geeksville, @casainho I've managed to build the firmware and flash to my 850C, but unfortunately neither of above mentioned fixes seem to work. I made some investigations as @casainho told me and figured out that the screen becomes white after call lcd_set_backlight_intensity(20). That means that display doesn't get initialised after call to bafang_500C_lcd_init() I've also tried to call some low-level (as I assume) painting functions like lcd_pixel_set but couldn't see any effect: the screen remains all white. In other hand, calls to lcd_set_backlight_intensity do work, I even made a "fade in" effect for startup, it looks nice but it's still a white screen.

Will try now to dig into docs and specs.

geeksville commented 4 years ago

Oh. But you can see the display has valid contents before calling lcd_backlight_intensity?

Perhaps they are using a different voltage for the LCD backlight. Try looking at set backlight intensity implementation and using a larger/smaller value.

Congrats on joining the devgroup btw. 😁

(Sent from a phone - please ignore typos)

On Mon, Sep 16, 2019, 07:30 Roman Novikov notifications@github.com wrote:

Hi @geeksville https://github.com/geeksville, @casainho https://github.com/casainho I've managed to build the firmware and flash to my 850C, but unfortunately neither of above mentioned fixes seem to work. I made some investigations as @casainho https://github.com/casainho told me and figured out that the screen becomes white after call lcd_set_backlight_intensity(20). That means that display doesn't get initialised after call to bafang_500C_lcd_init() I've also tried to call some low-level (as I assume) painting functions like lcd_pixel_set but couldn't see any effect: the screen remains all white. In other hand, calls to lcd_set_backlight_intensity do work, I even made a "fade in" effect for startup, it looks nice but it's still a white screen.

Will try now to dig into docs and specs.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/OpenSource-EBike-firmware/Color_LCD/issues/9?email_source=notifications&email_token=AABXB2KGHQKWNYTJXDQAI5TQJ6KA3A5CNFSM4IWYN542YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6ZK37I#issuecomment-531803645, or mute the thread https://github.com/notifications/unsubscribe-auth/AABXB2MIHG4NUHY3X4ZHLZ3QJ6KA3ANCNFSM4IWYN54Q .

r0mko commented 4 years ago

I can't see any content on the screen neither before, not after calling lcd_backlight_intensity. My primary guess for now is that the display is not initialized correctly. I mean that magic in the bafang_500C_lcd_init function seems to be not sufficient for this particular version of LCD.

Thanks! I'm glad to join your team. Hopefully I can be helpful. At least this is much more engaging and interesting than boring C++ autonomous driving stuff from my work.

geeksville commented 4 years ago

Oh I see! Ok in a few hours I'll check in some code that reads the display ctrlr part/mfg number. Are you able to set breakpoints in eclipse? You could then see what your board has?

r0mko commented 4 years ago

I'm not using Eclipse (I've chosen Qt Creator to my taste) and I don't have my 850C open, so I'm using a DIY bootloader (USB-UART and +36V line from a battery via Windows APT Burn Tools). So I'm not able to set breakpoints or somehow debug the code on the fly.

geeksville commented 4 years ago

ooh - I think I've figured out how to force my screen to also be stuck the white screen (with just a minor change to our lcd write timing). I'm now debugging.

r0mko commented 4 years ago

Interesting. Would be great to figure out timing for my LCD. I compared init sequences from original firmware against ours by reading the assembly provided by @casainho and found no differences, but I'm not very familiar with ARM assembly. Still wondering if GPIO output do drive the display is correct (just a mad guess, what if the display controller doesn't even receive commands due to error in addressing)

geeksville commented 4 years ago

I think a contributing factor is that in the current checked in code, we assert CS only once and hold it down forever. This works fine as we never do a transaction that the display controller doesn't like.

While adding support for reading registers from the display controller I accidentally did a bogus transaction and then forever after the display controller chip was hosed. I bet their little state machine starts from scratch each time it gets CS asserted to it. I'm now doing an experiment where I assert CS for each transaction (a command + set of write payload or a command + a set of read bytes) but leave it unasserted otherwise.

Also, from looking at the code (not measured with an oscope/LA) our timing for pulsing the write signal is possibly marginal (the datasheet says tPWLW is 30ns). I'm changing it to this:

void lcd_write_cycle() { // pulse low WR pin tPWLW min time 30ns (shortest possible CPU cycle on our CPU is 9ns) FIXME GPIOC->BRR = LCD_WRITEPIN; asm volatile( "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ); GPIOC->BSRR = LCD_WRITE__PIN;

// FIXME, total write cycle min time is 100ns, we are probably fine, but nothing is currently guaranteeing it

}

r0mko commented 4 years ago

Added a very dumb delay in lcd_write_command between GPIOC->BRR = LCD_WRITEPIN; delay_ms(1); GPIOC->BSRR = LCD_WRITEPIN; and voila! I got this. Green rectangle is my experiment:

Untitled-1

r0mko commented 4 years ago

Now I'll try to fix flip

geeksville commented 4 years ago

yay! I guess that was it! I think I'll still put in a change to assert CS only for each transaction, because it will make us more resiliant in the case we have bad transactions in the future.

geeksville commented 4 years ago

for your local test, you'll also want a similar delay in lcd_write_data_8bits

r0mko commented 4 years ago

nops doesn't seem to work, at least 4 of them. UPD: 10 don't work either. GPIOC->BRR = LCD_WRITEPIN; asm volatile( "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ... and more ... ); GPIOC->BSRR = LCD_WRITE__PIN;

r0mko commented 4 years ago

for your local test, you'll also want a similar delay in lcd_write_data_8bits (I bet that explains that green blob - with misc data bytes getting lost)

green blob is absolutely normal, I just experimented with HW_FillFrame

geeksville commented 4 years ago

gotcha!

geeksville commented 4 years ago

I guess whatever chip is in your device needs a fair amount more than 30ns for the write pulse. the 1ms delay will be way too slow though. I'll check in my code so you only have to change one place and I'll make it so you can experiment with the delay length.

r0mko commented 4 years ago

Wait a minute, I'll try to build this with -O0 (now it's -O2)

r0mko commented 4 years ago

Nope, OPT=0 also does not work. Trying to make a dummy loop. Do we have precise timers in STM32? There's a more elegant way to make a delay of 30 ns, I guess

geeksville commented 4 years ago

if you want to use this version it might make it easier for you to fuzz the write pulse length.

geeksville commented 4 years ago

yah - there is a nice ns level timer in the stm32, but we aren't using it and I haven't looked up how it works. ;-) If you'd like to add support for it that would be awesome. (I probably won't have time for a while)

r0mko commented 4 years ago

dummy loop seems to work with 80 cycles; 30 was not sufficient :-) Oh BTW these strange undocumented init commands (0xE4, 0xF0, 0xF3) seems to be necessary. Without them I get this (see pics) IMG_6309 IMG_6310

geeksville commented 4 years ago

ooh interesting! I think your display controller isn't a ILI9481. I'll go ahead and finish adding the read support, so we can read out the vendor info from the controller and figure out what it is.

r0mko commented 4 years ago

Voilá! Flip fixed. IMG_6311

casainho commented 4 years ago

Hmmm, I wish the writing could still be fast. But anyway, this is amazing news!!!!