Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of Smart Response XE display #673

Closed
wants to merge 0 commits into from

Conversation

twasilczyk
Copy link
Contributor

Implementation is monochrome only for now (the display is 4-level grayscale) until the new display APIs get merged from TomSaw's branch.

examples/srxe/display/main.cpp Outdated Show resolved Hide resolved
src/modm/board/srxe/board.hpp Outdated Show resolved Hide resolved
src/modm/driver/display/st7586s_impl.hpp Outdated Show resolved Hide resolved
@twasilczyk twasilczyk force-pushed the develop branch 3 times, most recently from c3e1336 to d12edd8 Compare August 31, 2021 06:43
@twasilczyk twasilczyk marked this pull request as ready for review September 2, 2021 05:14
@twasilczyk
Copy link
Contributor Author

Okay, I think this is ready to go. I'm pretty happy with this code and with how your library supports good code.

Honorable mentions:

  • all commands+data is sent to the display via full structs and not a bunch of uint8_t's
  • no magic numbers, entire protocol is pretty self-explanatory (see initialization code)
  • LittleEndian<> and BigEndian<> templates, I always wanted to code them. See SetVop on how I used it.

Challenges:

  • it's not easy to run unit tests on Ubuntu (I have 20.04.2 LTS) which doesn't ship with gcc 10
  • avr-gcc shipped with modm doesn't support std::is_constant_evaluated (that's C++20 symbol)
  • why SPI::transferBlocking requires uint8_t* and doesn't just accept void* pointers? See sendCommand
  • is register type explosion expected? I got NLineInversion, NLineInversion_t, LineInversionType and LineInversionType_t for a single register
  • I'm still not sure why MonochromeGraphicDisplayHorizontal didn't work. I didn't dig deep though.

Copy link
Contributor

@TomSaw TomSaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a quick look for now.
For consistence to ssd1306_register.hpp, st7586s_protocol.hpp should be st7586s_register.hpp.

src/modm/driver/display/st7586s_protocol.hpp Outdated Show resolved Hide resolved
src/modm/driver/display/st7586s_protocol.hpp Outdated Show resolved Hide resolved
src/modm/driver/display/st7586s_protocol.hpp Outdated Show resolved Hide resolved
@twasilczyk
Copy link
Contributor Author

Just a quick look for now.
For consistence to ssd1306_register.hpp, st7586s_protocol.hpp should be st7586s_register.hpp.

I also had this thought, but these are not registers (but commands and their payloads) and definitely not defines. Thoughts?

@TomSaw
Copy link
Contributor

TomSaw commented Sep 2, 2021

Just a quick look for now.
For consistence to ssd1306_register.hpp, st7586s_protocol.hpp should be st7586s_register.hpp.

I also had this thought, but these are not registers (but commands and their payloads) and definitely not defines. Thoughts?

Hardware-interfaces are likely a chaotic mix of registers, commands, protocols... more precise distinctions are taken up with the naming of enum's -> check other driver-headers!

I think it's an old convention to collect such things in one box called register for the benefit of consistence.

@twasilczyk
Copy link
Contributor Author

Just a quick look for now.
For consistence to ssd1306_register.hpp, st7586s_protocol.hpp should be st7586s_register.hpp.

I also had this thought, but these are not registers (but commands and their payloads) and definitely not defines. Thoughts?

Hardware-interfaces are likely a chaotic mix of registers, commands, protocols... more precise distinctions are taken up with the naming of enum's -> check other driver-headers!

I think it's an old convention to collect such things in one box called register for the benefit of consistence.

modm doesn't seem to stick to a single name for this stuff. Interface definitions are scattered around files named: _defines, _transport, _register, _definitions, _data, _constants. register is only used by ssd1306 driver actually.

@salkinium, what's your take? I don't think this library should stick to old conventions, but that's not my call at the end of the day :)

@salkinium salkinium self-requested a review September 3, 2021 06:31
@TomSaw TomSaw mentioned this pull request Sep 3, 2021
@TomSaw
Copy link
Contributor

TomSaw commented Sep 3, 2021

Have proposed my best solution of grayscale-support for st7586 in #670

Copy link
Contributor Author

@twasilczyk twasilczyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have proposed my best solution of grayscale-support for st7586 in #670

I’ll debate a little on the details later, but agree overall. I’ll wait with grayscale mode until you merge your PR.

src/modm/driver/display/st7586s.hpp Outdated Show resolved Hide resolved
src/modm/driver/display/st7586s.hpp Outdated Show resolved Hide resolved
Copy link
Contributor

@TomSaw TomSaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologizes for the chopped review. I'm fighting with my IDEs github extension, for now falling back to the browser. So here's part 3/3 :P

I leave the review of your endianness-edits @salkinium cause haven't enough background.

Comment on lines 83 to 88
modm_assert(x < Width, "st4586s.sc.x", "x >= Width", x);
modm_assert(x + w <= Width, "st4586s.sc.xw", "x + w >= Width", x + w);
modm_assert(y < Height, "st4586s.sc.y", "y >= Height", y);
modm_assert(y + h <= Height, "st4586s.sc.yh", "y + h >= Height", y + h);
modm_assert((x % pixelsPerByte) == 0, "st4586s.sc.x%", "x is not a multiply of PBB", x);
modm_assert((w % pixelsPerByte) == 0, "st4586s.sc.w%", "w is not a multiply of PBB", w);
Copy link
Contributor

@TomSaw TomSaw Sep 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These asserts evaluate all-over-again runtime :/

-> Why do you need setClipping to be public? Witch case requires the app-writer to call this directly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is going to be slow. However, you can use modm_assert_continue_fail_debug, which will still evaluate at runtime, however only in debug profile. I think that's a good compromise to find nasty bugs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Holy cow. Didn't you have a longer name for a regular assertion that doesn't get executed in debug mode? ;)

I was rather hoping for something along the lines:

  • CHECK(condition) - evaluates in debug build only
  • CHECK_ALWAYS(condition) - evaluates both in debug and release

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, not happy about it either. Here's some explanation of what I'm trying to describe: https://modm.io/reference/module/modm-architecture-assert/#assertion-types

void
St7586s<SPI, CS, RST, DC, Width, Height>::initialize()
{
namespace payload = impl::st7586s::payload;
Copy link
Contributor

@TomSaw TomSaw Sep 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can place using payload = impl::st586s::payload within class declaration to spare repetitions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid you can't define a namespace inside a class.

error: 'payload' in namespace 'modm::impl::st7586s' does not name a type

src/modm/driver/display/st7586s_impl.hpp Outdated Show resolved Hide resolved
Comment on lines 45 to 46
RST::reset();
RST::setOutput();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RST::setOutput(false); // same result

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah. I was actually hoping it would work this way, but the API scared me off. As it turns out, it wasn't API, but a mere implementation with swapped argument naming:

gpio_D4.hpp:

void setOutput(bool status);

While the TLD interface (gpio.hpp) has it:

void setOutput(bool value);

@salkinium: is this a typo? I was digging what status means and I had an impression it's something about pull-ups or port config.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a typo, it should reflect the architecture interface API.

src/modm/driver/display/st7586s_impl.hpp Outdated Show resolved Hide resolved
src/modm/driver/display/st7586s_impl.hpp Outdated Show resolved Hide resolved
src/modm/driver/display/st7586s_impl.hpp Outdated Show resolved Hide resolved
src/modm/driver/display/st7586s_impl.hpp Outdated Show resolved Hide resolved
@TomSaw
Copy link
Contributor

TomSaw commented Sep 4, 2021

modm doesn't seem to stick to a single name for this stuff. Interface definitions are scattered around files named: _defines, _transport, _register, _definitions, _data, _constants. register is only used by ssd1306 driver actually.

@salkinium, what's your take? I don't think this library should stick to old conventions, but that's not my call at the end of the day :)

There should be a standard!? I prefer _defines cause it takes the classic culture from ANSI-C. Anything else is already too tight.

Copy link
Contributor

@TomSaw TomSaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_

src/modm/math/utils/bit_operation.hpp Outdated Show resolved Hide resolved
src/modm/driver/display/st7586s_protocol.hpp Outdated Show resolved Hide resolved
Comment on lines 83 to 88
modm_assert(x < Width, "st4586s.sc.x", "x >= Width", x);
modm_assert(x + w <= Width, "st4586s.sc.xw", "x + w >= Width", x + w);
modm_assert(y < Height, "st4586s.sc.y", "y >= Height", y);
modm_assert(y + h <= Height, "st4586s.sc.yh", "y + h >= Height", y + h);
modm_assert((x % pixelsPerByte) == 0, "st4586s.sc.x%", "x is not a multiply of PBB", x);
modm_assert((w % pixelsPerByte) == 0, "st4586s.sc.w%", "w is not a multiply of PBB", w);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is going to be slow. However, you can use modm_assert_continue_fail_debug, which will still evaluate at runtime, however only in debug profile. I think that's a good compromise to find nasty bugs.

src/modm/driver/display/st7586s_protocol.hpp Outdated Show resolved Hide resolved
@salkinium
Copy link
Member

avr-gcc shipped with modm doesn't support std::is_constant_evaluated (that's C++20 symbol)

GCC supports it since v9, so I suspect maybe a problem with combining constexpr and modm_always_inline?

why SPI::transferBlocking requires uint8_t* and doesn't just accept void* pointers? See sendCommand

void* just requires more casting for the average use-case, since you typically store buffers as uint8_t*.

modm doesn't seem to stick to a single name for this stuff. Interface definitions are scattered around files named: _defines, _transport, _register, _definitions, _data, _constants. register is only used by ssd1306 driver actually.

There isn't really a convention from my side. We typically allow the wild west to sprout until it creates enough annoyance to warrant a alignment to a convention. So far the convention has been: There should be only one header file per driver (ideally identically named as the lbuild module) that you can include that pulls in everything you need, the rest is implementation detail.

@TomSaw
Copy link
Contributor

TomSaw commented Sep 4, 2021

It's mainly just historic convention to have just one header file which pulls in everything that is needed. We can remove this construct completely and instead just #pragma once and then #include "st7586s.hpp", which will also make IDE code completion work in this file, since it's pulling in the correct definitions.

(Ok, this file is dependency free, so you don't need the #include "st7586s.hpp" part, but in the st7586s.hpp_impl.hpp file that can be used).

😋 Smaller Boilerplate... Wunderbar! Copy that

@twasilczyk
Copy link
Contributor Author

avr-gcc shipped with modm doesn't support std::is_constant_evaluated (that's C++20 symbol)

GCC supports it since v9, so I suspect maybe a problem with combining constexpr and modm_always_inline?

Looks like it's just not there:

error: 'is_constant_evaluated' is not a member of 'std'

I know the root cause is likely in modm's avr-gcc fork and it's fixable there. But I'm already pretty deep in this rabbit hole :).

why SPI::transferBlocking requires uint8_t* and doesn't just accept void* pointers? See sendCommand

void* just requires more casting for the average use-case, since you typically store buffers as uint8_t*.

Does it? I'm pretty sure there's actually no casting needed in user code if the function accepts void* or const void*. Is there?

Copy link
Member

@salkinium salkinium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with this, thanks!

@twasilczyk
Copy link
Contributor Author

Sorry for push+force push (the first one was a WIP commit on a new driver, the second was to remove it). Current state should be the same as approved.

@salkinium
Copy link
Member

Whoops I wanted to rebased, but pushed my develop branch to your fork. I merged it manually.
Let's use feature branches in future ;-P

@salkinium
Copy link
Member

I know the root cause is likely in modm's avr-gcc fork and it's fixable there. But I'm already pretty deep in this rabbit hole :).

No, it's probably an issue with our custom libstdcpp not having set the _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED define? It's a bit weird, since the lib config should enable it automatically? cc @chris-durand

@chris-durand
Copy link
Member

@twasilczyk Did you include the type_traits header for std::is_constant_evaluated? I can't reproduce the issue.

@twasilczyk
Copy link
Contributor Author

Huh, it was missing type_traits. Apparently when built for ARM, this header gets pulled in by some other header. I'll make a follow-up PR, but not today.

@salkinium salkinium added this to the 2021q3 milestone Sep 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

4 participants