diff --git a/mxgui/drivers/display_stm32f4discovery.cpp b/mxgui/drivers/display_stm32f4discovery.cpp index 23b0a9d36d04e3bb6f11abde6c6c5bcc5f3362c1..3194f1829c8d154410218a7e955506d752133809 100644 --- a/mxgui/drivers/display_stm32f4discovery.cpp +++ b/mxgui/drivers/display_stm32f4discovery.cpp @@ -47,1456 +47,1457 @@ using namespace miosix; defined(_BOARD_STM32F429ZI_SKYWARD_GS_PARAFOIL) || \ defined(_BOARD_STM32F429ZI_HRE_TEST_STAND) || \ defined(_BOARD_STM32F429ZI_SKYWARD_PYXIS_AUXILIARY) || \ - defined(_BOARD_STM32F429ZI_SKYWARD_PARAFOIL) + defined(_BOARD_STM32F429ZI_SKYWARD_PARAFOIL) || \ + defined(_BOARD_STM32F429ZI_SKYWARD_RIG) namespace mxgui { -// Control interface -typedef Gpio<GPIOF_BASE, 7> scl; // SPI SCK -typedef Gpio<GPIOF_BASE, 9> sda; // SPI MOSI -typedef Gpio<GPIOC_BASE, 2> csx; // SPI CS -typedef Gpio<GPIOD_BASE, 13> dcx; // Data/command -typedef Gpio<GPIOD_BASE, 12> rdx; // Used only un parallel mode -typedef Gpio<GPIOD_BASE, 11> te; // Tearing effect output from display, unused -// Pixel sync interface -typedef Gpio<GPIOF_BASE, 10> en; -typedef Gpio<GPIOG_BASE, 7> dotclk; -typedef Gpio<GPIOA_BASE, 4> vsync; -typedef Gpio<GPIOC_BASE, 6> hsync; -// Pixel data bus -typedef Gpio<GPIOC_BASE, 10> r0; // r2 -typedef Gpio<GPIOB_BASE, 0> r1; // r3 -typedef Gpio<GPIOA_BASE, 11> r2; // r4 -typedef Gpio<GPIOA_BASE, 12> r3; // r5 -typedef Gpio<GPIOB_BASE, 1> r4; // r6 -typedef Gpio<GPIOG_BASE, 6> r5; // r7 -typedef Gpio<GPIOA_BASE, 6> g0; // g2 -typedef Gpio<GPIOG_BASE, 10> g1; // g3 -typedef Gpio<GPIOB_BASE, 10> g2; // g4 -typedef Gpio<GPIOB_BASE, 11> g3; // g5 -typedef Gpio<GPIOC_BASE, 7> g4; // g6 -typedef Gpio<GPIOD_BASE, 3> g5; // g7 -typedef Gpio<GPIOD_BASE, 6> b0; // b2 -typedef Gpio<GPIOG_BASE, 11> b1; // b3 -typedef Gpio<GPIOG_BASE, 12> b2; // b4 -typedef Gpio<GPIOA_BASE, 3> b3; // b5 -typedef Gpio<GPIOB_BASE, 8> b4; // b6 -typedef Gpio<GPIOB_BASE, 9> b5; // b7 - -/** - * Send and receive a byte through SPI5 - * \param c byte to send - * \return byte received - */ -static unsigned char spi5sendRev(unsigned char c = 0) -{ - SPI5->DR = c; - while ((SPI5->SR & SPI_SR_RXNE) == 0) - ; - return SPI5->DR; -} - -/** - * Send a command to the ILI9341 display controller - * \param cmd command - * \param len length of the (optional) argument, or 0 for commands without - * arguments. - */ -static void sendCmd(unsigned char cmd, int len, ...) -{ - dcx::low(); - csx::low(); - spi5sendRev(cmd); - csx::high(); - delayUs(1); - dcx::high(); - va_list arg; - va_start(arg, len); - for (int i = 0; i < len; i++) + // Control interface + typedef Gpio<GPIOF_BASE, 7> scl; // SPI SCK + typedef Gpio<GPIOF_BASE, 9> sda; // SPI MOSI + typedef Gpio<GPIOC_BASE, 2> csx; // SPI CS + typedef Gpio<GPIOD_BASE, 13> dcx; // Data/command + typedef Gpio<GPIOD_BASE, 12> rdx; // Used only un parallel mode + typedef Gpio<GPIOD_BASE, 11> te; // Tearing effect output from display, unused + // Pixel sync interface + typedef Gpio<GPIOF_BASE, 10> en; + typedef Gpio<GPIOG_BASE, 7> dotclk; + typedef Gpio<GPIOA_BASE, 4> vsync; + typedef Gpio<GPIOC_BASE, 6> hsync; + // Pixel data bus + typedef Gpio<GPIOC_BASE, 10> r0; // r2 + typedef Gpio<GPIOB_BASE, 0> r1; // r3 + typedef Gpio<GPIOA_BASE, 11> r2; // r4 + typedef Gpio<GPIOA_BASE, 12> r3; // r5 + typedef Gpio<GPIOB_BASE, 1> r4; // r6 + typedef Gpio<GPIOG_BASE, 6> r5; // r7 + typedef Gpio<GPIOA_BASE, 6> g0; // g2 + typedef Gpio<GPIOG_BASE, 10> g1; // g3 + typedef Gpio<GPIOB_BASE, 10> g2; // g4 + typedef Gpio<GPIOB_BASE, 11> g3; // g5 + typedef Gpio<GPIOC_BASE, 7> g4; // g6 + typedef Gpio<GPIOD_BASE, 3> g5; // g7 + typedef Gpio<GPIOD_BASE, 6> b0; // b2 + typedef Gpio<GPIOG_BASE, 11> b1; // b3 + typedef Gpio<GPIOG_BASE, 12> b2; // b4 + typedef Gpio<GPIOA_BASE, 3> b3; // b5 + typedef Gpio<GPIOB_BASE, 8> b4; // b6 + typedef Gpio<GPIOB_BASE, 9> b5; // b7 + + /** + * Send and receive a byte through SPI5 + * \param c byte to send + * \return byte received + */ + static unsigned char spi5sendRev(unsigned char c = 0) + { + SPI5->DR = c; + while ((SPI5->SR & SPI_SR_RXNE) == 0) + ; + return SPI5->DR; + } + + /** + * Send a command to the ILI9341 display controller + * \param cmd command + * \param len length of the (optional) argument, or 0 for commands without + * arguments. + */ + static void sendCmd(unsigned char cmd, int len, ...) { + dcx::low(); csx::low(); - spi5sendRev(va_arg(arg, int)); + spi5sendRev(cmd); csx::high(); delayUs(1); + dcx::high(); + va_list arg; + va_start(arg, len); + for (int i = 0; i < len; i++) + { + csx::low(); + spi5sendRev(va_arg(arg, int)); + csx::high(); + delayUs(1); + } + va_end(arg); } - va_end(arg); -} -void registerDisplayHook(DisplayManager &dm) -{ - dm.registerDisplay(&DisplayImpl::instance()); -} + void registerDisplayHook(DisplayManager &dm) + { + dm.registerDisplay(&DisplayImpl::instance()); + } -// -// class DisplayImpl -// + // + // class DisplayImpl + // -DisplayImpl &DisplayImpl::instance() -{ - static DisplayImpl instance; - return instance; -} + DisplayImpl &DisplayImpl::instance() + { + static DisplayImpl instance; + return instance; + } -void DisplayImpl::doTurnOn() -{ - LTDC->GCR |= LTDC_GCR_LTDCEN; - Thread::sleep(40); - sendCmd(0x29, 0); // LCD_DISPLAY_ON -} + void DisplayImpl::doTurnOn() + { + LTDC->GCR |= LTDC_GCR_LTDCEN; + Thread::sleep(40); + sendCmd(0x29, 0); // LCD_DISPLAY_ON + } -void DisplayImpl::doTurnOff() -{ - sendCmd(0x28, 0); // LCD_DISPLAY_OFF - LTDC->GCR &= ~LTDC_GCR_LTDCEN; -} + void DisplayImpl::doTurnOff() + { + sendCmd(0x28, 0); // LCD_DISPLAY_OFF + LTDC->GCR &= ~LTDC_GCR_LTDCEN; + } -void DisplayImpl::doSetBrightness(int brt) {} + void DisplayImpl::doSetBrightness(int brt) {} -pair<short int, short int> DisplayImpl::doGetSize() const -{ - return make_pair(height, width); -} + pair<short int, short int> DisplayImpl::doGetSize() const + { + return make_pair(height, width); + } -void DisplayImpl::write(Point p, const char *text) -{ - font.draw(*this, textColor, p, text); -} + void DisplayImpl::write(Point p, const char *text) + { + font.draw(*this, textColor, p, text); + } -void DisplayImpl::clippedWrite(Point p, Point a, Point b, const char *text) -{ - font.clippedDraw(*this, textColor, p, a, b, text); -} + void DisplayImpl::clippedWrite(Point p, Point a, Point b, const char *text) + { + font.clippedDraw(*this, textColor, p, a, b, text); + } -void DisplayImpl::clear(Color color) -{ - clear(Point(0, 0), Point(width - 1, height - 1), color); -} + void DisplayImpl::clear(Color color) + { + clear(Point(0, 0), Point(width - 1, height - 1), color); + } -void DisplayImpl::clear(Point p1, Point p2, Color color) -{ - if (p1.x() < 0 || p2.x() < p1.x() || p2.x() >= width || p1.y() < 0 || - p2.y() < p1.y() || p2.y() >= height) - return; - if ((color & 0xff) == (color >> 8)) + void DisplayImpl::clear(Point p1, Point p2, Color color) { - // Can use memset - if (p1.x() == 0 && p2.x() == width - 1) - { - // Can merge lines - memset(framebuffer1 + p1.y() * width, color, - (p2.y() - p1.y() + 1) * width * bpp); - } - else + if (p1.x() < 0 || p2.x() < p1.x() || p2.x() >= width || p1.y() < 0 || + p2.y() < p1.y() || p2.y() >= height) + return; + if ((color & 0xff) == (color >> 8)) { - // Can't merge lines - Color *ptr = framebuffer1 + p1.x() + width * p1.y(); - short len = p2.x() - p1.x() + 1; - for (short i = p1.y(); i <= p2.y(); i++) + // Can use memset + if (p1.x() == 0 && p2.x() == width - 1) { - memset(ptr, color, len * bpp); - ptr += width; + // Can merge lines + memset(framebuffer1 + p1.y() * width, color, + (p2.y() - p1.y() + 1) * width * bpp); } - } - } - else - { - // Can't use memset - if (p1.x() == 0 && p2.x() == width - 1) - { - // Can merge lines - Color *ptr = framebuffer1 + p1.y() * width; - int numPixels = (p2.y() - p1.y() + 1) * width; - // This loop is worth unrolling - for (int i = 0; i < numPixels / 4; i++) + else { - *ptr++ = color; - *ptr++ = color; - *ptr++ = color; - *ptr++ = color; + // Can't merge lines + Color *ptr = framebuffer1 + p1.x() + width * p1.y(); + short len = p2.x() - p1.x() + 1; + for (short i = p1.y(); i <= p2.y(); i++) + { + memset(ptr, color, len * bpp); + ptr += width; + } } - for (int i = 0; i < (numPixels & 3); i++) - *ptr++ = color; } else { - // Can't merge lines - Color *ptr = framebuffer1 + p1.x() + width * p1.y(); - short len = p2.x() - p1.x() + 1; - for (short i = p1.y(); i <= p2.y(); i++) + // Can't use memset + if (p1.x() == 0 && p2.x() == width - 1) { - for (short j = 0; j < len; j++) + // Can merge lines + Color *ptr = framebuffer1 + p1.y() * width; + int numPixels = (p2.y() - p1.y() + 1) * width; + // This loop is worth unrolling + for (int i = 0; i < numPixels / 4; i++) + { + *ptr++ = color; + *ptr++ = color; *ptr++ = color; - ptr += width - len; + *ptr++ = color; + } + for (int i = 0; i < (numPixels & 3); i++) + *ptr++ = color; + } + else + { + // Can't merge lines + Color *ptr = framebuffer1 + p1.x() + width * p1.y(); + short len = p2.x() - p1.x() + 1; + for (short i = p1.y(); i <= p2.y(); i++) + { + for (short j = 0; j < len; j++) + *ptr++ = color; + ptr += width - len; + } } } } -} -void DisplayImpl::beginPixel() {} - -void DisplayImpl::setPixel(Point p, Color color) -{ - int offset = p.x() + p.y() * width; - if (offset < 0 || offset >= numPixels) - return; - *(framebuffer1 + offset) = color; -} + void DisplayImpl::beginPixel() {} -void DisplayImpl::line(Point a, Point b, Color color) -{ - // Horizontal line speed optimization - if (a.y() == b.y()) + void DisplayImpl::setPixel(Point p, Color color) { - short minx = min(a.x(), b.x()); - short maxx = max(a.x(), b.x()); - if (minx < 0 || maxx >= width || a.y() < 0 || a.y() >= height) + int offset = p.x() + p.y() * width; + if (offset < 0 || offset >= numPixels) return; - Color *ptr = framebuffer1 + minx + width * a.y(); - for (short i = minx; i <= maxx; i++) - *ptr++ = color; - return; + *(framebuffer1 + offset) = color; } - // Vertical line speed optimization - if (a.x() == b.x()) + + void DisplayImpl::line(Point a, Point b, Color color) { - short miny = min(a.y(), b.y()); - short maxy = max(a.y(), b.y()); - if (a.x() < 0 || a.x() >= width || miny < 0 || maxy >= height) + // Horizontal line speed optimization + if (a.y() == b.y()) + { + short minx = min(a.x(), b.x()); + short maxx = max(a.x(), b.x()); + if (minx < 0 || maxx >= width || a.y() < 0 || a.y() >= height) + return; + Color *ptr = framebuffer1 + minx + width * a.y(); + for (short i = minx; i <= maxx; i++) + *ptr++ = color; return; - Color *ptr = framebuffer1 + a.x() + width * miny; - for (short i = miny; i <= maxy; i++) + } + // Vertical line speed optimization + if (a.x() == b.x()) { - *ptr = color; - ptr += width; + short miny = min(a.y(), b.y()); + short maxy = max(a.y(), b.y()); + if (a.x() < 0 || a.x() >= width || miny < 0 || maxy >= height) + return; + Color *ptr = framebuffer1 + a.x() + width * miny; + for (short i = miny; i <= maxy; i++) + { + *ptr = color; + ptr += width; + } + return; } - return; + // General case + Line::draw(*this, a, b, color); } - // General case - Line::draw(*this, a, b, color); -} -void DisplayImpl::scanLine(Point p, const Color *colors, unsigned short length) -{ - if (p.x() < 0 || - static_cast<int>(p.x()) + static_cast<int>(length) > width || - p.y() < 0 || p.y() >= height) - return; - Color *ptr = framebuffer1 + p.x() + p.y() * width; - memcpy(ptr, colors, length * bpp); -} + void DisplayImpl::scanLine(Point p, const Color *colors, unsigned short length) + { + if (p.x() < 0 || + static_cast<int>(p.x()) + static_cast<int>(length) > width || + p.y() < 0 || p.y() >= height) + return; + Color *ptr = framebuffer1 + p.x() + p.y() * width; + memcpy(ptr, colors, length * bpp); + } -Color *DisplayImpl::getScanLineBuffer() { return buffer; } + Color *DisplayImpl::getScanLineBuffer() { return buffer; } -void DisplayImpl::scanLineBuffer(Point p, unsigned short length) -{ - int offset = p.x() + p.y() * width; - if (offset < 0 || offset >= numPixels) - return; - memcpy(framebuffer1 + offset, buffer, length * bpp); -} + void DisplayImpl::scanLineBuffer(Point p, unsigned short length) + { + int offset = p.x() + p.y() * width; + if (offset < 0 || offset >= numPixels) + return; + memcpy(framebuffer1 + offset, buffer, length * bpp); + } -void DisplayImpl::drawImage(Point p, const ImageBase &img) -{ - short int xEnd = p.x() + img.getWidth() - 1; - short int yEnd = p.y() + img.getHeight() - 1; - if (p.x() < 0 || p.y() < 0 || xEnd < p.x() || yEnd < p.y() || - xEnd >= width || yEnd >= height) - return; + void DisplayImpl::drawImage(Point p, const ImageBase &img) + { + short int xEnd = p.x() + img.getWidth() - 1; + short int yEnd = p.y() + img.getHeight() - 1; + if (p.x() < 0 || p.y() < 0 || xEnd < p.x() || yEnd < p.y() || + xEnd >= width || yEnd >= height) + return; - // const unsigned short *imgData=img.getData(); - // if(imgData!=0) - // { - // //TODO Optimized version for in-memory images - // } else - img.draw(*this, p); -} + // const unsigned short *imgData=img.getData(); + // if(imgData!=0) + // { + // //TODO Optimized version for in-memory images + // } else + img.draw(*this, p); + } -void DisplayImpl::clippedDrawImage(Point p, Point a, Point b, - const ImageBase &img) -{ - // if(img.getData()==0) - // { - img.clippedDraw(*this, p, a, b); - return; - // } //else optimized version for memory-loaded images - // //TODO: optimize - // } -} - -void DisplayImpl::drawRectangle(Point a, Point b, Color c) -{ - line(a, Point(b.x(), a.y()), c); - line(Point(b.x(), a.y()), b, c); - line(b, Point(a.x(), b.y()), c); - line(Point(a.x(), b.y()), a, c); -} - -DisplayImpl::pixel_iterator DisplayImpl::begin(Point p1, Point p2, - IteratorDirection d) -{ - bool fail = false; - if (p1.x() < 0 || p1.y() < 0 || p2.x() < 0 || p2.y() < 0) - fail = true; - if (p1.x() >= width || p1.y() >= height || p2.x() >= width || - p2.y() >= height) - fail = true; - if (p2.x() < p1.x() || p2.y() < p1.y()) - fail = true; - if (fail) + void DisplayImpl::clippedDrawImage(Point p, Point a, Point b, + const ImageBase &img) { - // Return invalid (dummy) iterators - this->last = pixel_iterator(); - return this->last; + // if(img.getData()==0) + // { + img.clippedDraw(*this, p, a, b); + return; + // } //else optimized version for memory-loaded images + // //TODO: optimize + // } } - // Set the last iterator to a suitable one-past-the last value - if (d == DR) - this->last = pixel_iterator(Point(p2.x() + 1, p1.y()), p2, d, this); - else - this->last = pixel_iterator(Point(p1.x(), p2.y() + 1), p2, d, this); + void DisplayImpl::drawRectangle(Point a, Point b, Color c) + { + line(a, Point(b.x(), a.y()), c); + line(Point(b.x(), a.y()), b, c); + line(b, Point(a.x(), b.y()), c); + line(Point(a.x(), b.y()), a, c); + } - return pixel_iterator(p1, p2, d, this); -} + DisplayImpl::pixel_iterator DisplayImpl::begin(Point p1, Point p2, + IteratorDirection d) + { + bool fail = false; + if (p1.x() < 0 || p1.y() < 0 || p2.x() < 0 || p2.y() < 0) + fail = true; + if (p1.x() >= width || p1.y() >= height || p2.x() >= width || + p2.y() >= height) + fail = true; + if (p2.x() < p1.x() || p2.y() < p1.y()) + fail = true; + if (fail) + { + // Return invalid (dummy) iterators + this->last = pixel_iterator(); + return this->last; + } -DisplayImpl::~DisplayImpl() {} + // Set the last iterator to a suitable one-past-the last value + if (d == DR) + this->last = pixel_iterator(Point(p2.x() + 1, p1.y()), p2, d, this); + else + this->last = pixel_iterator(Point(p1.x(), p2.y() + 1), p2, d, this); -DisplayImpl::DisplayImpl() - : framebuffer1(reinterpret_cast<unsigned short *>(0xd0600000)), - buffer(framebuffer1 + numPixels) -{ - { - FastInterruptDisableLock dLock; - // PLLSAI runs @ 192MHz, both Q and R outputs are divided by 4 so 48MHz - RCC->PLLSAICFGR = 4 << 28 | 4 << 24 | 192 << 6; - // PLLSAI R output divided by 8 resulting in a 6MHz LTDC clock - RCC->DCKCFGR = 2 << 16; - RCC->CR |= RCC_CR_PLLSAION; + return pixel_iterator(p1, p2, d, this); } - while ((RCC->CR & RCC_CR_PLLSAIRDY) == 0) - ; + DisplayImpl::~DisplayImpl() {} + DisplayImpl::DisplayImpl() + : framebuffer1(reinterpret_cast<unsigned short *>(0xd0600000)), + buffer(framebuffer1 + numPixels) { - FastInterruptDisableLock dLock; + { + FastInterruptDisableLock dLock; + // PLLSAI runs @ 192MHz, both Q and R outputs are divided by 4 so 48MHz + RCC->PLLSAICFGR = 4 << 28 | 4 << 24 | 192 << 6; + // PLLSAI R output divided by 8 resulting in a 6MHz LTDC clock + RCC->DCKCFGR = 2 << 16; + RCC->CR |= RCC_CR_PLLSAION; + } - scl::mode(Mode::ALTERNATE); - scl::alternateFunction(5); // SPI5 - sda::mode(Mode::ALTERNATE); - sda::alternateFunction(5); - csx::mode(Mode::OUTPUT); - csx::high(); - dcx::mode(Mode::OUTPUT); - rdx::mode(Mode::OUTPUT); - rdx::low(); // Original fw seems to leave it low - - en::mode(Mode::ALTERNATE); - en::alternateFunction(14); - dotclk::mode(Mode::ALTERNATE); - dotclk::alternateFunction(14); - vsync::mode(Mode::ALTERNATE); - vsync::alternateFunction(14); - hsync::mode(Mode::ALTERNATE); - hsync::alternateFunction(14); - r0::mode(Mode::ALTERNATE); - r0::alternateFunction(14); - r1::mode(Mode::ALTERNATE); - r1::alternateFunction(14); - r2::mode(Mode::ALTERNATE); - r2::alternateFunction(14); - r3::mode(Mode::ALTERNATE); - r3::alternateFunction(14); - r4::mode(Mode::ALTERNATE); - r4::alternateFunction(14); - r5::mode(Mode::ALTERNATE); - r5::alternateFunction(14); - g0::mode(Mode::ALTERNATE); - g0::alternateFunction(14); - g1::mode(Mode::ALTERNATE); - g1::alternateFunction(14); - g2::mode(Mode::ALTERNATE); - g2::alternateFunction(14); - g3::mode(Mode::ALTERNATE); - g3::alternateFunction(14); - g4::mode(Mode::ALTERNATE); - g4::alternateFunction(14); - g5::mode(Mode::ALTERNATE); - g5::alternateFunction(14); - b0::mode(Mode::ALTERNATE); - b0::alternateFunction(14); - b1::mode(Mode::ALTERNATE); - b1::alternateFunction(14); - b2::mode(Mode::ALTERNATE); - b2::alternateFunction(14); - b3::mode(Mode::ALTERNATE); - b3::alternateFunction(14); - b4::mode(Mode::ALTERNATE); - b4::alternateFunction(14); - b5::mode(Mode::ALTERNATE); - b5::alternateFunction(14); - - RCC->APB2ENR |= RCC_APB2ENR_LTDCEN | RCC_APB2ENR_SPI5EN; - RCC_SYNC(); - } + while ((RCC->CR & RCC_CR_PLLSAIRDY) == 0) + ; - SPI5->CR1 = SPI_CR1_SSM // Sowtware CS - | SPI_CR1_SSI // Software CS high - | SPI_CR1_SPE // SPI enabled - | (3 << 3) // Divide input clock by 16: 84/16=5.25MHz - | SPI_CR1_MSTR; // Master mode - Thread::sleep(1); + { + FastInterruptDisableLock dLock; + + scl::mode(Mode::ALTERNATE); + scl::alternateFunction(5); // SPI5 + sda::mode(Mode::ALTERNATE); + sda::alternateFunction(5); + csx::mode(Mode::OUTPUT); + csx::high(); + dcx::mode(Mode::OUTPUT); + rdx::mode(Mode::OUTPUT); + rdx::low(); // Original fw seems to leave it low + + en::mode(Mode::ALTERNATE); + en::alternateFunction(14); + dotclk::mode(Mode::ALTERNATE); + dotclk::alternateFunction(14); + vsync::mode(Mode::ALTERNATE); + vsync::alternateFunction(14); + hsync::mode(Mode::ALTERNATE); + hsync::alternateFunction(14); + r0::mode(Mode::ALTERNATE); + r0::alternateFunction(14); + r1::mode(Mode::ALTERNATE); + r1::alternateFunction(14); + r2::mode(Mode::ALTERNATE); + r2::alternateFunction(14); + r3::mode(Mode::ALTERNATE); + r3::alternateFunction(14); + r4::mode(Mode::ALTERNATE); + r4::alternateFunction(14); + r5::mode(Mode::ALTERNATE); + r5::alternateFunction(14); + g0::mode(Mode::ALTERNATE); + g0::alternateFunction(14); + g1::mode(Mode::ALTERNATE); + g1::alternateFunction(14); + g2::mode(Mode::ALTERNATE); + g2::alternateFunction(14); + g3::mode(Mode::ALTERNATE); + g3::alternateFunction(14); + g4::mode(Mode::ALTERNATE); + g4::alternateFunction(14); + g5::mode(Mode::ALTERNATE); + g5::alternateFunction(14); + b0::mode(Mode::ALTERNATE); + b0::alternateFunction(14); + b1::mode(Mode::ALTERNATE); + b1::alternateFunction(14); + b2::mode(Mode::ALTERNATE); + b2::alternateFunction(14); + b3::mode(Mode::ALTERNATE); + b3::alternateFunction(14); + b4::mode(Mode::ALTERNATE); + b4::alternateFunction(14); + b5::mode(Mode::ALTERNATE); + b5::alternateFunction(14); + + RCC->APB2ENR |= RCC_APB2ENR_LTDCEN | RCC_APB2ENR_SPI5EN; + RCC_SYNC(); + } - // - // ILI9341 power up sequence -- begin - // - sendCmd(0xca, 3, 0xc3, 0x08, 0x50); // undocumented command - sendCmd(0xcf, 3, 0x00, 0xc1, 0x30); // LCD_POWERB - sendCmd(0xed, 4, 0x64, 0x03, 0x12, 0x81); // LCD_POWER_SEQ - sendCmd(0xe8, 3, 0x85, 0x00, 0x78); // LCD_DTCA - sendCmd(0xcb, 5, 0x39, 0x2c, 0x00, 0x34, 0x02); // LCD_POWERA - sendCmd(0xf7, 1, 0x20); // LCD_PRC - sendCmd(0xea, 2, 0x00, 0x00); // LCD_DTCB - sendCmd(0xb1, 2, 0x00, 0x1b); // LCD_FRMCTR1 - sendCmd(0xb6, 2, 0x0a, 0xa2); // LCD_DFC - sendCmd(0xc0, 1, 0x10); // LCD_POWER1 - sendCmd(0xc1, 1, 0x10); // LCD_POWER2 - sendCmd(0xc5, 2, 0x45, 0x15); // LCD_VCOM1 - sendCmd(0xc7, 1, 0x90); // LCD_VCOM2 - sendCmd(0x36, 1, 0xc8); // LCD_MAC - sendCmd(0xf2, 1, 0x00); // LCD_3GAMMA_EN - sendCmd(0xb0, 1, 0xc2); // LCD_RGB_INTERFACE - sendCmd(0xb6, 4, 0x0a, 0xa7, 0x27, 0x04); // LCD_DFC - sendCmd(0x2a, 4, 0x00, 0x00, 0x00, 0xef); // LCD_COLUMN_ADDR - sendCmd(0x2b, 4, 0x00, 0x00, 0x01, 0x3f); // LCD_PAGE_ADDR - sendCmd(0xf6, 3, 0x01, 0x00, 0x06); // LCD_INTERFACE - sendCmd(0x2c, 0); // LCD_GRAM - Thread::sleep(200); - sendCmd(0x26, 1, 0x01); // LCD_GAMMA - sendCmd(0xe0, 15, 0x0f, 0x29, 0x24, 0x0c, 0x0e, 0x09, 0x4e, 0x78, 0x3c, - 0x09, 0x13, 0x05, 0x17, 0x11, 0x00); // LCD_PGAMMA - sendCmd(0xe1, 15, 0x00, 0x16, 0x1b, 0x04, 0x11, 0x07, 0x31, 0x33, 0x42, - 0x05, 0x0c, 0x0a, 0x28, 0x2f, 0x0f); // LCD_NGAMMA - sendCmd(0x11, 0); // LCD_SLEEP_OUT - Thread::sleep(200); - sendCmd(0x29, 0); // LCD_DISPLAY_ON - sendCmd(0x2c, 0); // LCD_GRAM - // - // ILI9341 power up sequence -- end - // + SPI5->CR1 = SPI_CR1_SSM // Sowtware CS + | SPI_CR1_SSI // Software CS high + | SPI_CR1_SPE // SPI enabled + | (3 << 3) // Divide input clock by 16: 84/16=5.25MHz + | SPI_CR1_MSTR; // Master mode + Thread::sleep(1); + + // + // ILI9341 power up sequence -- begin + // + sendCmd(0xca, 3, 0xc3, 0x08, 0x50); // undocumented command + sendCmd(0xcf, 3, 0x00, 0xc1, 0x30); // LCD_POWERB + sendCmd(0xed, 4, 0x64, 0x03, 0x12, 0x81); // LCD_POWER_SEQ + sendCmd(0xe8, 3, 0x85, 0x00, 0x78); // LCD_DTCA + sendCmd(0xcb, 5, 0x39, 0x2c, 0x00, 0x34, 0x02); // LCD_POWERA + sendCmd(0xf7, 1, 0x20); // LCD_PRC + sendCmd(0xea, 2, 0x00, 0x00); // LCD_DTCB + sendCmd(0xb1, 2, 0x00, 0x1b); // LCD_FRMCTR1 + sendCmd(0xb6, 2, 0x0a, 0xa2); // LCD_DFC + sendCmd(0xc0, 1, 0x10); // LCD_POWER1 + sendCmd(0xc1, 1, 0x10); // LCD_POWER2 + sendCmd(0xc5, 2, 0x45, 0x15); // LCD_VCOM1 + sendCmd(0xc7, 1, 0x90); // LCD_VCOM2 + sendCmd(0x36, 1, 0xc8); // LCD_MAC + sendCmd(0xf2, 1, 0x00); // LCD_3GAMMA_EN + sendCmd(0xb0, 1, 0xc2); // LCD_RGB_INTERFACE + sendCmd(0xb6, 4, 0x0a, 0xa7, 0x27, 0x04); // LCD_DFC + sendCmd(0x2a, 4, 0x00, 0x00, 0x00, 0xef); // LCD_COLUMN_ADDR + sendCmd(0x2b, 4, 0x00, 0x00, 0x01, 0x3f); // LCD_PAGE_ADDR + sendCmd(0xf6, 3, 0x01, 0x00, 0x06); // LCD_INTERFACE + sendCmd(0x2c, 0); // LCD_GRAM + Thread::sleep(200); + sendCmd(0x26, 1, 0x01); // LCD_GAMMA + sendCmd(0xe0, 15, 0x0f, 0x29, 0x24, 0x0c, 0x0e, 0x09, 0x4e, 0x78, 0x3c, + 0x09, 0x13, 0x05, 0x17, 0x11, 0x00); // LCD_PGAMMA + sendCmd(0xe1, 15, 0x00, 0x16, 0x1b, 0x04, 0x11, 0x07, 0x31, 0x33, 0x42, + 0x05, 0x0c, 0x0a, 0x28, 0x2f, 0x0f); // LCD_NGAMMA + sendCmd(0x11, 0); // LCD_SLEEP_OUT + Thread::sleep(200); + sendCmd(0x29, 0); // LCD_DISPLAY_ON + sendCmd(0x2c, 0); // LCD_GRAM + // + // ILI9341 power up sequence -- end + // + + memset(framebuffer1, 0, height * width * bpp); + + const unsigned int hsync = 10; // hsync timing + const unsigned int vsync = 2; // vsync timing + const unsigned int hbp = 20; // horizontal back porch + const unsigned int vbp = 2; // vertical back porch + const unsigned int hfp = 10; // horizontal front porch + const unsigned int vfp = 4; // vertical front porch + enum + { + ARGB8888 = 0, + RGB888 = 1, + RGB565 = 2, + ARGB1555 = 3, + ARGB4444 = 4, + L8 = 5, + AL44 = 6, + AL88 = 7 + }; + // Configure timings + LTDC->SSCR = (hsync - 1) << 16 | (vsync - 1); + LTDC->BPCR = (hsync + hbp - 1) << 16 | (vsync + vbp - 1); + LTDC->AWCR = (hsync + hbp + width - 1) << 16 | (vsync + vbp + height - 1); + LTDC->TWCR = (hfp + hsync + hbp + width - 1) << 16 | + (vfp + vsync + vbp + height - 1); + // Configre background color (black)) + LTDC->BCCR = 0; + // Enable layer 2 + LTDC_Layer2->CR = 0 // Disable palette mode + | 0 // Disable color keying + | LTDC_LxCR_LEN; // Enable layer + LTDC_Layer2->WHPCR = (hsync + hbp + width - 1) << 16 | (hsync + hbp); + LTDC_Layer2->WVPCR = (vsync + vbp + height - 1) << 16 | (vsync + vbp); + LTDC_Layer2->CKCR = 0; + LTDC_Layer2->PFCR = RGB565; + LTDC_Layer2->CACR = 0xff; // Alpha=1 + LTDC_Layer2->DCCR = 0; + LTDC_Layer2->CFBAR = reinterpret_cast<unsigned int>(framebuffer1); + LTDC_Layer2->CFBLR = + (width * bpp) << 16 | (width * bpp + 3); // Packed lines + LTDC_Layer2->CFBLNR = height; + // Write to shadow registers + LTDC->SRCR = LTDC_SRCR_IMR; + // Finally enable the display + LTDC->GCR = 0 // hsync active low + | 0 // vsync active low + | 0 // enable active low + | 0 // input pixel clock + | 0 // no dithering + | LTDC_GCR_LTDCEN; // Display enabled + + setFont(droid11); + setTextColor(make_pair(Color(0xffff), Color(0x0000))); + clear(black); + } - memset(framebuffer1, 0, height * width * bpp); + Color DisplayImpl::pixel_iterator::dummy; - const unsigned int hsync = 10; // hsync timing - const unsigned int vsync = 2; // vsync timing - const unsigned int hbp = 20; // horizontal back porch - const unsigned int vbp = 2; // vertical back porch - const unsigned int hfp = 10; // horizontal front porch - const unsigned int vfp = 4; // vertical front porch - enum - { - ARGB8888 = 0, - RGB888 = 1, - RGB565 = 2, - ARGB1555 = 3, - ARGB4444 = 4, - L8 = 5, - AL44 = 6, - AL88 = 7 - }; - // Configure timings - LTDC->SSCR = (hsync - 1) << 16 | (vsync - 1); - LTDC->BPCR = (hsync + hbp - 1) << 16 | (vsync + vbp - 1); - LTDC->AWCR = (hsync + hbp + width - 1) << 16 | (vsync + vbp + height - 1); - LTDC->TWCR = (hfp + hsync + hbp + width - 1) << 16 | - (vfp + vsync + vbp + height - 1); - // Configre background color (black)) - LTDC->BCCR = 0; - // Enable layer 2 - LTDC_Layer2->CR = 0 // Disable palette mode - | 0 // Disable color keying - | LTDC_LxCR_LEN; // Enable layer - LTDC_Layer2->WHPCR = (hsync + hbp + width - 1) << 16 | (hsync + hbp); - LTDC_Layer2->WVPCR = (vsync + vbp + height - 1) << 16 | (vsync + vbp); - LTDC_Layer2->CKCR = 0; - LTDC_Layer2->PFCR = RGB565; - LTDC_Layer2->CACR = 0xff; // Alpha=1 - LTDC_Layer2->DCCR = 0; - LTDC_Layer2->CFBAR = reinterpret_cast<unsigned int>(framebuffer1); - LTDC_Layer2->CFBLR = - (width * bpp) << 16 | (width * bpp + 3); // Packed lines - LTDC_Layer2->CFBLNR = height; - // Write to shadow registers - LTDC->SRCR = LTDC_SRCR_IMR; - // Finally enable the display - LTDC->GCR = 0 // hsync active low - | 0 // vsync active low - | 0 // enable active low - | 0 // input pixel clock - | 0 // no dithering - | LTDC_GCR_LTDCEN; // Display enabled - - setFont(droid11); - setTextColor(make_pair(Color(0xffff), Color(0x0000))); - clear(black); -} - -Color DisplayImpl::pixel_iterator::dummy; - -} // namespace mxgui - -#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY +} // namespace mxgui + +#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY #ifdef _BOARD_STM32F469NI_STM32F469I_DISCO namespace mxgui { -// Control interface - -// Pixel sync interface -typedef Gpio<GPIOF_BASE, 10> en; -typedef Gpio<GPIOG_BASE, 7> dotclk; -typedef Gpio<GPIOA_BASE, 4> vsync; -typedef Gpio<GPIOC_BASE, 6> hsync; -// Pixel data bus -typedef Gpio<GPIOC_BASE, 10> r0; // r2 -typedef Gpio<GPIOJ_BASE, 2> r1; // r3 -typedef Gpio<GPIOA_BASE, 11> r2; // r4 -typedef Gpio<GPIOA_BASE, 12> r3; // r5 -typedef Gpio<GPIOJ_BASE, 5> r4; // r6 -typedef Gpio<GPIOA_BASE, 6> g0; // g2 -typedef Gpio<GPIOG_BASE, 10> g1; // g3 AF9 -typedef Gpio<GPIOJ_BASE, 13> g2; // g4 AF9 -typedef Gpio<GPIOH_BASE, 4> g3; // g5 AF9 -typedef Gpio<GPIOC_BASE, 7> g4; // g6 -typedef Gpio<GPIOD_BASE, 3> g5; // g7 -typedef Gpio<GPIOD_BASE, 6> b0; // b2 -typedef Gpio<GPIOG_BASE, 11> b1; // b3 -typedef Gpio<GPIOG_BASE, 12> b2; // b4 AF9 -typedef Gpio<GPIOA_BASE, 3> b3; // b5 -typedef Gpio<GPIOB_BASE, 8> b4; // b6 - -void shortWrite(uint8_t param0, uint8_t param1) -{ - // Command FIFO Empty - while ((DSI->GPSR & DSI_GPSR_CMDFE) == 0) - ; + // Control interface + + // Pixel sync interface + typedef Gpio<GPIOF_BASE, 10> en; + typedef Gpio<GPIOG_BASE, 7> dotclk; + typedef Gpio<GPIOA_BASE, 4> vsync; + typedef Gpio<GPIOC_BASE, 6> hsync; + // Pixel data bus + typedef Gpio<GPIOC_BASE, 10> r0; // r2 + typedef Gpio<GPIOJ_BASE, 2> r1; // r3 + typedef Gpio<GPIOA_BASE, 11> r2; // r4 + typedef Gpio<GPIOA_BASE, 12> r3; // r5 + typedef Gpio<GPIOJ_BASE, 5> r4; // r6 + typedef Gpio<GPIOA_BASE, 6> g0; // g2 + typedef Gpio<GPIOG_BASE, 10> g1; // g3 AF9 + typedef Gpio<GPIOJ_BASE, 13> g2; // g4 AF9 + typedef Gpio<GPIOH_BASE, 4> g3; // g5 AF9 + typedef Gpio<GPIOC_BASE, 7> g4; // g6 + typedef Gpio<GPIOD_BASE, 3> g5; // g7 + typedef Gpio<GPIOD_BASE, 6> b0; // b2 + typedef Gpio<GPIOG_BASE, 11> b1; // b3 + typedef Gpio<GPIOG_BASE, 12> b2; // b4 AF9 + typedef Gpio<GPIOA_BASE, 3> b3; // b5 + typedef Gpio<GPIOB_BASE, 8> b4; // b6 + + void shortWrite(uint8_t param0, uint8_t param1) + { + // Command FIFO Empty + while ((DSI->GPSR & DSI_GPSR_CMDFE) == 0) + ; - DSI->GHCR = (0x15 | // DSI_DCS_SHORT_PKT_WRITE_P1 - (0 << 6) | // Virtual Channel ID - (param0 << 8) | (param1 << 16)); -} + DSI->GHCR = (0x15 | // DSI_DCS_SHORT_PKT_WRITE_P1 + (0 << 6) | // Virtual Channel ID + (param0 << 8) | (param1 << 16)); + } -void longWrite(uint32_t numParams, uint32_t param0, uint8_t *pParams) -{ - // Command FIFO Empty - while ((DSI->GPSR & DSI_GPSR_CMDFE) == 0) - ; + void longWrite(uint32_t numParams, uint32_t param0, uint8_t *pParams) + { + // Command FIFO Empty + while ((DSI->GPSR & DSI_GPSR_CMDFE) == 0) + ; + + uint32_t uicounter = 0; + while (uicounter < numParams) + { + if (uicounter == 0x00) + { + DSI->GPDR = (param0 | ((*(pParams + uicounter)) << 8) | + ((*(pParams + uicounter + 1)) << 16) | + ((*(pParams + uicounter + 2)) << 24)); + uicounter += 3; + } + else + { + DSI->GPDR = ((*(pParams + uicounter)) | + ((*(pParams + uicounter + 1)) << 8) | + ((*(pParams + uicounter + 2)) << 16) | + ((*(pParams + uicounter + 3)) << 24)); + uicounter += 4; + } + } - uint32_t uicounter = 0; - while (uicounter < numParams) + DSI->GHCR = (0x39 | // DSI_DCS_LONG_PKT_WRITE + (0 << 6) | // Virtual Channel Id + (((numParams + 1) & 0x00FF) << 8) | + ((((numParams + 1) & 0xFF00) >> 8) << 16)); + } + + void sendCmd(uint32_t numParams, uint8_t *pParams) { - if (uicounter == 0x00) + if (numParams <= 1) { - DSI->GPDR = (param0 | ((*(pParams + uicounter)) << 8) | - ((*(pParams + uicounter + 1)) << 16) | - ((*(pParams + uicounter + 2)) << 24)); - uicounter += 3; + shortWrite(pParams[0], pParams[1]); } else { - DSI->GPDR = ((*(pParams + uicounter)) | - ((*(pParams + uicounter + 1)) << 8) | - ((*(pParams + uicounter + 2)) << 16) | - ((*(pParams + uicounter + 3)) << 24)); - uicounter += 4; + longWrite(numParams, pParams[numParams], pParams); } } - DSI->GHCR = (0x39 | // DSI_DCS_LONG_PKT_WRITE - (0 << 6) | // Virtual Channel Id - (((numParams + 1) & 0x00FF) << 8) | - ((((numParams + 1) & 0xFF00) >> 8) << 16)); -} - -void sendCmd(uint32_t numParams, uint8_t *pParams) -{ - if (numParams <= 1) + void registerDisplayHook(DisplayManager &dm) { - shortWrite(pParams[0], pParams[1]); + dm.registerDisplay(&DisplayImpl::instance()); } - else - { - longWrite(numParams, pParams[numParams], pParams); - } -} - -void registerDisplayHook(DisplayManager &dm) -{ - dm.registerDisplay(&DisplayImpl::instance()); -} -// -// class DisplayImpl -// + // + // class DisplayImpl + // -DisplayImpl &DisplayImpl::instance() -{ - static DisplayImpl instance; - return instance; -} + DisplayImpl &DisplayImpl::instance() + { + static DisplayImpl instance; + return instance; + } -void DisplayImpl::doTurnOn() -{ - LTDC->GCR |= LTDC_GCR_LTDCEN; - Thread::sleep(40); - uint8_t set_display_on[] = {0x29, 0x00}; - sendCmd(0, set_display_on); -} + void DisplayImpl::doTurnOn() + { + LTDC->GCR |= LTDC_GCR_LTDCEN; + Thread::sleep(40); + uint8_t set_display_on[] = {0x29, 0x00}; + sendCmd(0, set_display_on); + } -void DisplayImpl::doTurnOff() -{ - uint8_t set_display_off[] = {0x28, 0x00}; - sendCmd(0, set_display_off); - LTDC->GCR &= ~LTDC_GCR_LTDCEN; -} + void DisplayImpl::doTurnOff() + { + uint8_t set_display_off[] = {0x28, 0x00}; + sendCmd(0, set_display_off); + LTDC->GCR &= ~LTDC_GCR_LTDCEN; + } -void DisplayImpl::doSetBrightness(int brt) {} + void DisplayImpl::doSetBrightness(int brt) {} -pair<short int, short int> DisplayImpl::doGetSize() const -{ - return make_pair(height, width); -} + pair<short int, short int> DisplayImpl::doGetSize() const + { + return make_pair(height, width); + } -void DisplayImpl::write(Point p, const char *text) -{ - font.draw(*this, textColor, p, text); -} + void DisplayImpl::write(Point p, const char *text) + { + font.draw(*this, textColor, p, text); + } -void DisplayImpl::clippedWrite(Point p, Point a, Point b, const char *text) -{ - font.clippedDraw(*this, textColor, p, a, b, text); -} + void DisplayImpl::clippedWrite(Point p, Point a, Point b, const char *text) + { + font.clippedDraw(*this, textColor, p, a, b, text); + } -void DisplayImpl::clear(Color color) -{ - clear(Point(0, 0), Point(width - 1, height - 1), color); -} + void DisplayImpl::clear(Color color) + { + clear(Point(0, 0), Point(width - 1, height - 1), color); + } -void DisplayImpl::clear(Point p1, Point p2, Color color) -{ - if (p1.x() < 0 || p2.x() < p1.x() || p2.x() >= width || p1.y() < 0 || - p2.y() < p1.y() || p2.y() >= height) - return; - if ((color & 0xff) == (color >> 8)) + void DisplayImpl::clear(Point p1, Point p2, Color color) { - // Can use memset - if (p1.x() == 0 && p2.x() == width - 1) - { - // Can merge lines - memset(framebuffer1 + p1.y() * width, color, - (p2.y() - p1.y() + 1) * width * bpp); - } - else + if (p1.x() < 0 || p2.x() < p1.x() || p2.x() >= width || p1.y() < 0 || + p2.y() < p1.y() || p2.y() >= height) + return; + if ((color & 0xff) == (color >> 8)) { - // Can't merge lines - Color *ptr = framebuffer1 + p1.x() + width * p1.y(); - short len = p2.x() - p1.x() + 1; - for (short i = p1.y(); i <= p2.y(); i++) + // Can use memset + if (p1.x() == 0 && p2.x() == width - 1) { - memset(ptr, color, len * bpp); - ptr += width; + // Can merge lines + memset(framebuffer1 + p1.y() * width, color, + (p2.y() - p1.y() + 1) * width * bpp); } - } - } - else - { - // Can't use memset - if (p1.x() == 0 && p2.x() == width - 1) - { - // Can merge lines - Color *ptr = framebuffer1 + p1.y() * width; - int numPixels = (p2.y() - p1.y() + 1) * width; - // This loop is worth unrolling - for (int i = 0; i < numPixels / 4; i++) + else { - *ptr++ = color; - *ptr++ = color; - *ptr++ = color; - *ptr++ = color; + // Can't merge lines + Color *ptr = framebuffer1 + p1.x() + width * p1.y(); + short len = p2.x() - p1.x() + 1; + for (short i = p1.y(); i <= p2.y(); i++) + { + memset(ptr, color, len * bpp); + ptr += width; + } } - for (int i = 0; i < (numPixels & 3); i++) - *ptr++ = color; } else { - // Can't merge lines - Color *ptr = framebuffer1 + p1.x() + width * p1.y(); - short len = p2.x() - p1.x() + 1; - for (short i = p1.y(); i <= p2.y(); i++) + // Can't use memset + if (p1.x() == 0 && p2.x() == width - 1) { - for (short j = 0; j < len; j++) + // Can merge lines + Color *ptr = framebuffer1 + p1.y() * width; + int numPixels = (p2.y() - p1.y() + 1) * width; + // This loop is worth unrolling + for (int i = 0; i < numPixels / 4; i++) + { + *ptr++ = color; + *ptr++ = color; *ptr++ = color; - ptr += width - len; + *ptr++ = color; + } + for (int i = 0; i < (numPixels & 3); i++) + *ptr++ = color; + } + else + { + // Can't merge lines + Color *ptr = framebuffer1 + p1.x() + width * p1.y(); + short len = p2.x() - p1.x() + 1; + for (short i = p1.y(); i <= p2.y(); i++) + { + for (short j = 0; j < len; j++) + *ptr++ = color; + ptr += width - len; + } } } } -} -void DisplayImpl::beginPixel() {} - -void DisplayImpl::setPixel(Point p, Color color) -{ - int offset = p.x() + p.y() * width; - if (offset < 0 || offset >= numPixels) - return; - *(framebuffer1 + offset) = color; -} + void DisplayImpl::beginPixel() {} -void DisplayImpl::line(Point a, Point b, Color color) -{ - // Horizontal line speed optimization - if (a.y() == b.y()) + void DisplayImpl::setPixel(Point p, Color color) { - short minx = min(a.x(), b.x()); - short maxx = max(a.x(), b.x()); - if (minx < 0 || maxx >= width || a.y() < 0 || a.y() >= height) + int offset = p.x() + p.y() * width; + if (offset < 0 || offset >= numPixels) return; - Color *ptr = framebuffer1 + minx + width * a.y(); - for (short i = minx; i <= maxx; i++) - *ptr++ = color; - return; + *(framebuffer1 + offset) = color; } - // Vertical line speed optimization - if (a.x() == b.x()) + + void DisplayImpl::line(Point a, Point b, Color color) { - short miny = min(a.y(), b.y()); - short maxy = max(a.y(), b.y()); - if (a.x() < 0 || a.x() >= width || miny < 0 || maxy >= height) + // Horizontal line speed optimization + if (a.y() == b.y()) + { + short minx = min(a.x(), b.x()); + short maxx = max(a.x(), b.x()); + if (minx < 0 || maxx >= width || a.y() < 0 || a.y() >= height) + return; + Color *ptr = framebuffer1 + minx + width * a.y(); + for (short i = minx; i <= maxx; i++) + *ptr++ = color; return; - Color *ptr = framebuffer1 + a.x() + width * miny; - for (short i = miny; i <= maxy; i++) + } + // Vertical line speed optimization + if (a.x() == b.x()) { - *ptr = color; - ptr += width; + short miny = min(a.y(), b.y()); + short maxy = max(a.y(), b.y()); + if (a.x() < 0 || a.x() >= width || miny < 0 || maxy >= height) + return; + Color *ptr = framebuffer1 + a.x() + width * miny; + for (short i = miny; i <= maxy; i++) + { + *ptr = color; + ptr += width; + } + return; } - return; + // General case + Line::draw(*this, a, b, color); } - // General case - Line::draw(*this, a, b, color); -} -void DisplayImpl::scanLine(Point p, const Color *colors, unsigned short length) -{ - if (p.x() < 0 || - static_cast<int>(p.x()) + static_cast<int>(length) > width || - p.y() < 0 || p.y() >= height) - return; - Color *ptr = framebuffer1 + p.x() + p.y() * width; - memcpy(ptr, colors, length * bpp); -} - -Color *DisplayImpl::getScanLineBuffer() { return buffer; } + void DisplayImpl::scanLine(Point p, const Color *colors, unsigned short length) + { + if (p.x() < 0 || + static_cast<int>(p.x()) + static_cast<int>(length) > width || + p.y() < 0 || p.y() >= height) + return; + Color *ptr = framebuffer1 + p.x() + p.y() * width; + memcpy(ptr, colors, length * bpp); + } -void DisplayImpl::scanLineBuffer(Point p, unsigned short length) -{ - int offset = p.x() + p.y() * width; - if (offset < 0 || offset >= numPixels) - return; - memcpy(framebuffer1 + offset, buffer, length * bpp); -} + Color *DisplayImpl::getScanLineBuffer() { return buffer; } -void DisplayImpl::drawImage(Point p, const ImageBase &img) -{ - short int xEnd = p.x() + img.getWidth() - 1; - short int yEnd = p.y() + img.getHeight() - 1; - if (p.x() < 0 || p.y() < 0 || xEnd < p.x() || yEnd < p.y() || - xEnd >= width || yEnd >= height) - return; + void DisplayImpl::scanLineBuffer(Point p, unsigned short length) + { + int offset = p.x() + p.y() * width; + if (offset < 0 || offset >= numPixels) + return; + memcpy(framebuffer1 + offset, buffer, length * bpp); + } - // const unsigned short *imgData=img.getData(); - // if(imgData!=0) - // { - // //TODO Optimized version for in-memory images - // } else - img.draw(*this, p); -} + void DisplayImpl::drawImage(Point p, const ImageBase &img) + { + short int xEnd = p.x() + img.getWidth() - 1; + short int yEnd = p.y() + img.getHeight() - 1; + if (p.x() < 0 || p.y() < 0 || xEnd < p.x() || yEnd < p.y() || + xEnd >= width || yEnd >= height) + return; -void DisplayImpl::clippedDrawImage(Point p, Point a, Point b, - const ImageBase &img) -{ - // if(img.getData()==0) - // { - img.clippedDraw(*this, p, a, b); - return; - // } //else optimized version for memory-loaded images - // //TODO: optimize - // } -} - -void DisplayImpl::drawRectangle(Point a, Point b, Color c) -{ - line(a, Point(b.x(), a.y()), c); - line(Point(b.x(), a.y()), b, c); - line(b, Point(a.x(), b.y()), c); - line(Point(a.x(), b.y()), a, c); -} + // const unsigned short *imgData=img.getData(); + // if(imgData!=0) + // { + // //TODO Optimized version for in-memory images + // } else + img.draw(*this, p); + } -void DisplayImpl::update() { DSI->WCR |= DSI_WCR_LTDCEN; } + void DisplayImpl::clippedDrawImage(Point p, Point a, Point b, + const ImageBase &img) + { + // if(img.getData()==0) + // { + img.clippedDraw(*this, p, a, b); + return; + // } //else optimized version for memory-loaded images + // //TODO: optimize + // } + } -DisplayImpl::pixel_iterator DisplayImpl::begin(Point p1, Point p2, - IteratorDirection d) -{ - bool fail = false; - if (p1.x() < 0 || p1.y() < 0 || p2.x() < 0 || p2.y() < 0) - fail = true; - if (p1.x() >= width || p1.y() >= height || p2.x() >= width || - p2.y() >= height) - fail = true; - if (p2.x() < p1.x() || p2.y() < p1.y()) - fail = true; - if (fail) + void DisplayImpl::drawRectangle(Point a, Point b, Color c) { - // Return invalid (dummy) iterators - this->last = pixel_iterator(); - return this->last; + line(a, Point(b.x(), a.y()), c); + line(Point(b.x(), a.y()), b, c); + line(b, Point(a.x(), b.y()), c); + line(Point(a.x(), b.y()), a, c); } - // Set the last iterator to a suitable one-past-the last value - if (d == DR) - this->last = pixel_iterator(Point(p2.x() + 1, p1.y()), p2, d, this); - else - this->last = pixel_iterator(Point(p1.x(), p2.y() + 1), p2, d, this); + void DisplayImpl::update() { DSI->WCR |= DSI_WCR_LTDCEN; } - return pixel_iterator(p1, p2, d, this); -} + DisplayImpl::pixel_iterator DisplayImpl::begin(Point p1, Point p2, + IteratorDirection d) + { + bool fail = false; + if (p1.x() < 0 || p1.y() < 0 || p2.x() < 0 || p2.y() < 0) + fail = true; + if (p1.x() >= width || p1.y() >= height || p2.x() >= width || + p2.y() >= height) + fail = true; + if (p2.x() < p1.x() || p2.y() < p1.y()) + fail = true; + if (fail) + { + // Return invalid (dummy) iterators + this->last = pixel_iterator(); + return this->last; + } -DisplayImpl::~DisplayImpl() {} + // Set the last iterator to a suitable one-past-the last value + if (d == DR) + this->last = pixel_iterator(Point(p2.x() + 1, p1.y()), p2, d, this); + else + this->last = pixel_iterator(Point(p1.x(), p2.y() + 1), p2, d, this); -DisplayImpl::DisplayImpl() - : framebuffer1(reinterpret_cast<unsigned short *>(0xc0c00000)), - buffer(framebuffer1 + numPixels) -{ - /* This driver uses DSI interface in command mode, but it was firstly - * programmed in video mode. For this reason some instructions are still - * there but they don't actually affect the driver. For example these timing - * parameters are important in video mode, but in command mode they can take - * any value and the display still works. - */ - const unsigned int hsync = 12; // hsync timing - const unsigned int vsync = 120; // vsync timing - const unsigned int hbp = 12; // horizontal back porch - const unsigned int vbp = 120; // vertical back porch - const unsigned int hfp = 12; // horizontal front porch - const unsigned int vfp = 120; // vertical front porch - enum + return pixel_iterator(p1, p2, d, this); + } + + DisplayImpl::~DisplayImpl() {} + + DisplayImpl::DisplayImpl() + : framebuffer1(reinterpret_cast<unsigned short *>(0xc0c00000)), + buffer(framebuffer1 + numPixels) { - ARGB8888 = 0, - RGB888 = 1, - RGB565 = 2, - ARGB1555 = 3, - ARGB4444 = 4, - L8 = 5, - AL44 = 6, - AL88 = 7 - }; + /* This driver uses DSI interface in command mode, but it was firstly + * programmed in video mode. For this reason some instructions are still + * there but they don't actually affect the driver. For example these timing + * parameters are important in video mode, but in command mode they can take + * any value and the display still works. + */ + const unsigned int hsync = 12; // hsync timing + const unsigned int vsync = 120; // vsync timing + const unsigned int hbp = 12; // horizontal back porch + const unsigned int vbp = 120; // vertical back porch + const unsigned int hfp = 12; // horizontal front porch + const unsigned int vfp = 120; // vertical front porch + enum + { + ARGB8888 = 0, + RGB888 = 1, + RGB565 = 2, + ARGB1555 = 3, + ARGB4444 = 4, + L8 = 5, + AL44 = 6, + AL88 = 7 + }; // Parameters for DSI PLL // These values assume HSE oscillator is 8 MHz and system clock is 168 MHz #if HSE_VALUE != 8000000 #error The display driver requires an HSE oscillator running at 8 MHz #endif - const unsigned int IDF = 4; // must be in the range 1..7 - const unsigned int ODF = 1; // must be in the set {1, 2, 4, 8} - const unsigned int NDIV = 125; // must be in the range 10..125 - const unsigned int F_VCO = - (HSE_VALUE / IDF) * 2 * - NDIV; // 500 MHz - must be between 500 and 1000 MHz - const unsigned int F_PHY_MHz = - (F_VCO / (2 * ODF)) / - 1000000; // 250 MHz - HS clock for D-PHY must be between 80 and 500 MHz - const unsigned int lane_byte_clk = - F_VCO / (2 * ODF * 8); // 31,25 MHz - must be no more than 62,5 MHz - const unsigned int TXECLKDIV = - 2; // must be at least 2 and ensure lane_byte_clk/TXECLKDIV <= 20 MHz - const unsigned int pixel_clock = F_VCO / bpp; // 31,25 MHz - const unsigned int clock_ratio = lane_byte_clk / pixel_clock; - - memset(framebuffer1, 0, height * width * bpp); - - // Reset of screen by active low on GPIO PH7 - typedef Gpio<GPIOH_BASE, 7> reset; - reset::mode(Mode::OUTPUT); - reset::speed(Speed::_100MHz); - reset::low(); - Thread::sleep(20); - reset::high(); - Thread::sleep(10); - - // Enable clock for DSI and LTDC then force their reset - { - FastInterruptDisableLock dLock; - - en::mode(Mode::ALTERNATE); - en::alternateFunction(14); - en::speed(Speed::_100MHz); - dotclk::mode(Mode::ALTERNATE); - dotclk::alternateFunction(14); - dotclk::speed(Speed::_100MHz); - vsync::mode(Mode::ALTERNATE); - vsync::alternateFunction(14); - vsync::speed(Speed::_100MHz); - hsync::mode(Mode::ALTERNATE); - hsync::alternateFunction(14); - hsync::speed(Speed::_100MHz); - r0::mode(Mode::ALTERNATE); - r0::alternateFunction(14); - r0::speed(Speed::_100MHz); - r1::mode(Mode::ALTERNATE); - r1::alternateFunction(14); - r1::speed(Speed::_100MHz); - r2::mode(Mode::ALTERNATE); - r2::alternateFunction(14); - r2::speed(Speed::_100MHz); - r3::mode(Mode::ALTERNATE); - r3::alternateFunction(14); - r3::speed(Speed::_100MHz); - r4::mode(Mode::ALTERNATE); - r4::alternateFunction(14); - r4::speed(Speed::_100MHz); - g0::mode(Mode::ALTERNATE); - g0::alternateFunction(14); - g0::speed(Speed::_100MHz); - g1::mode(Mode::ALTERNATE); - g1::alternateFunction(9); - g1::speed(Speed::_100MHz); - g2::mode(Mode::ALTERNATE); - g2::alternateFunction(9); - g2::speed(Speed::_100MHz); - g3::mode(Mode::ALTERNATE); - g3::alternateFunction(9); - g3::speed(Speed::_100MHz); - g4::mode(Mode::ALTERNATE); - g4::alternateFunction(14); - g4::speed(Speed::_100MHz); - g5::mode(Mode::ALTERNATE); - g5::alternateFunction(14); - g5::speed(Speed::_100MHz); - b0::mode(Mode::ALTERNATE); - b0::alternateFunction(14); - b0::speed(Speed::_100MHz); - b1::mode(Mode::ALTERNATE); - b1::alternateFunction(14); - b1::speed(Speed::_100MHz); - b2::mode(Mode::ALTERNATE); - b2::alternateFunction(9); - b2::speed(Speed::_100MHz); - b3::mode(Mode::ALTERNATE); - b3::alternateFunction(14); - b3::speed(Speed::_100MHz); - b4::mode(Mode::ALTERNATE); - b4::alternateFunction(14); - b4::speed(Speed::_100MHz); - - RCC->APB2ENR |= RCC_APB2ENR_LTDCEN; - RCC_SYNC(); - RCC->APB2ENR |= RCC_APB2ENR_DSIEN; - RCC_SYNC(); - - RCC->APB2RSTR |= RCC_APB2RSTR_LTDCRST; - RCC->APB2RSTR &= ~RCC_APB2RSTR_LTDCRST; - - RCC->APB2RSTR |= RCC_APB2RSTR_DSIRST; - RCC->APB2RSTR &= ~RCC_APB2RSTR_DSIRST; - } - - // Configure PLLSAI for LTDC, turn it ON and wait for its lock - { - FastInterruptDisableLock dLock; - - // LTDC clock depends on PLL_M which is fixed at boot with value 8 - // It also depends on PLLSAI which can be freely configured - const unsigned int PLLSAI_N = 384; - const unsigned int PLLSAI_R = 7; - // const unsigned int PLLSAI_DIVR = 0; - - // Input VCO Frequency = HSE_VALUE/PPL_M must be between 1 and 2 MHz, so - // 8/8 = 1 MHz N must be in the range 50..432 and ensure a frequency - // between 100 and 432 MHz if N = 384 then 1 MHz * 384 = 384 MHz R must - // be in the range 2..7, we choose R = 7 so 384/7 = 54,857 MHz and then - // we divide it by 2 (setting DIVR to 0) to obtain 27,428 Mhz - - // Read PLLSAI_P and PLLSAI_Q values from PLLSAICFGR register - uint32_t PLLSAI_P = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIP) >> 16); - uint32_t PLLSAI_Q = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> 24); - // PLLSAI_VCO_Input = PLL_SOURCE/PLL_M - // PLLSAI_VCO_Output = PLLSAI_VCO_Input * PLLSAI_N - // LTDC_CLK(first level) = PLLSAI_VCO_Output/PLLSAI_R - RCC->PLLSAICFGR = (PLLSAI_N << 6) | (PLLSAI_P << 16) | - (PLLSAI_Q << 24) | (PLLSAI_R << 28); - // LTDC_CLK = LTDC_CLK(first level)/PLLSAI_DIVR - RCC->DCKCFGR = RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR; - - RCC->CR |= RCC_CR_PLLSAION; - } - while ((RCC->CR & RCC_CR_PLLSAIRDY) == 0) - ; - - /* Start LTDC configuration */ - // Configure timings - LTDC->SSCR = (hsync - 1) << 16 | (vsync - 1); - LTDC->BPCR = (hsync + hbp - 1) << 16 | (vsync + vbp - 1); - LTDC->AWCR = (hsync + hbp + width - 1) << 16 | (vsync + vbp + height - 1); - LTDC->TWCR = (hsync + hbp + width + hfp - 1) << 16 | - (vsync + vbp + height + vfp - 1); - - // Configure polarities (everything active high except data enabled) - LTDC->GCR |= - (LTDC_GCR_HSPOL | LTDC_GCR_VSPOL | LTDC_GCR_DEPOL | LTDC_GCR_PCPOL); - LTDC->GCR &= ~LTDC_GCR_DEPOL; - - // Configure background color - LTDC->BCCR = 0; - - // Configure the layer - // Horizontal start and stop position - LTDC_Layer1->WHPCR &= ~(LTDC_LxWHPCR_WHSTPOS | LTDC_LxWHPCR_WHSPPOS); - LTDC_Layer1->WHPCR = ((hsync + hbp + width - 1) << 16) | (hsync + hbp); - // Vertical start and stop position - LTDC_Layer1->WVPCR &= ~(LTDC_LxWVPCR_WVSTPOS | LTDC_LxWVPCR_WVSPPOS); - LTDC_Layer1->WVPCR = ((vsync + vbp + height - 1) << 16) | (vsync + vbp); - // Pixel format - LTDC_Layer1->PFCR &= ~(LTDC_LxPFCR_PF); - LTDC_Layer1->PFCR |= RGB565; - // Color frame buffer start address - LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD); - LTDC_Layer1->CFBAR = reinterpret_cast<unsigned int>(framebuffer1); - // Color frame buffer pitch in byte (multiply by 2 for RGB565) - LTDC_Layer1->CFBLR &= ~(LTDC_LxCFBLR_CFBP | LTDC_LxCFBLR_CFBLL); - LTDC_Layer1->CFBLR = (width * 2) << 16 | (width * 2 + 3); - // Frame buffer line number - LTDC_Layer1->CFBLNR &= ~(LTDC_LxCFBLNR_CFBLNBR); - LTDC_Layer1->CFBLNR = height; - // Default color values (black with no alpha) - LTDC_Layer1->DCCR &= ~(LTDC_LxDCCR_DCBLUE | LTDC_LxDCCR_DCGREEN | - LTDC_LxDCCR_DCRED | LTDC_LxDCCR_DCALPHA); - LTDC_Layer1->DCCR = 0; - // Specifies the constant alpha value - LTDC_Layer1->CACR &= ~(LTDC_LxCACR_CONSTA); - LTDC_Layer1->CACR = 255; - // Blending factors (constant alpha) - LTDC_Layer1->BFCR &= ~(LTDC_LxBFCR_BF2 | LTDC_LxBFCR_BF1); - LTDC_Layer1->BFCR = (0x400 | 0x5); - // Enable layer - LTDC_Layer1->CR |= LTDC_LxCR_LEN; - - // If needed enable dithering and color keying - LTDC_Layer1->CKCR = 0; - - // Reload shadow registers - LTDC->SRCR |= LTDC_SRCR_IMR; - - // Finally enable the display - LTDC->GCR |= LTDC_GCR_LTDCEN; - /* End LTDC configuration */ - - /* Start DSI configuration */ - // Turn on the DSI regulator and wait for the regulator ready - DSI->WRPCR |= DSI_WRPCR_REGEN; - while ((DSI->WISR & DSI_WISR_RRS) == 0) - ; - - // Configure the DSI PLL, turn it ON and wait for its lock - // F_VCO = (HSE_VALUE / IDF) * 2 * NDIV - // Lane_Byte_CLK = F_VCO / (2 * ODF * 8) - // F_VCO must be in the range from 500 MHz to 1 GHz - // To obtain 500 Mbit/s rate, Lane_Byte_CLK must be 31,25 MHz - // Since HSE_VALUE = 8 MHz this is possible with NDIV = 125, IDF = 4, ODF = - // 1 - DSI->WRPCR &= ~(DSI_WRPCR_PLL_NDIV | DSI_WRPCR_PLL_IDF | DSI_WRPCR_PLL_ODF); - DSI->WRPCR |= ((NDIV << 2) | (IDF << 11) | (ODF << 16)); - DSI->WRPCR |= DSI_WRPCR_PLLEN; - while ((DSI->WISR & DSI_WISR_PLLLS) == 0) - ; - - // Configure the D-PHY parameters - // Calculate the bit period in high-speed mode in unit of 0.25 ns (UIX4) - // The equation is: UIX4 = IntegerPart( (1000/F_PHY_MHz) * 4 ) - // Where: F_PHY_MHz = (NDIV * HSE_MHz) / (IDF * ODF) - DSI->WPCR[0] &= ~DSI_WPCR0_UIX4; - DSI->WPCR[0] |= (1000 / F_PHY_MHz) * 4; - // Disable all error interrupts and reset the Error Mask - DSI->IER[0] = 0; - DSI->IER[1] = 0; - // Configure the number of active data lanes (just one out of two for 16 - // bpp) - DSI->PCONFR &= ~DSI_PCONFR_NL; - DSI->PCONFR |= 1; - // Set automatic clock lane control - DSI->CLCR |= (DSI_CLCR_DPCC | DSI_CLCR_ACR); - // Time for LP/HS and HS/LP transitions for both clock lane and data lanes - DSI->CLTCR |= (40 << 16) // HS to LP - | (40 << 0); // LP to HS - DSI->DLTCR |= (20 << 24) // HS to LP - | (20 << 16); // HS to LP - // Stop wait time (don't know how much should it be, random high number in 8 - // bit) - DSI->PCONFR &= ~DSI_PCONFR_SW_TIME; - DSI->PCONFR |= (100 << 8); - - // Configure the DSI Host timing - // DSI->CCR |= (... << 8); // timeout clock configuration non dice nulla... - // Configure clock speed for low-power mode - DSI->CCR &= ~DSI_CCR_TXECKDIV; - DSI->CCR |= TXECLKDIV; - - // Configure the DSI Host flow control and DBI interface - DSI->PCR &= ~(DSI_PCR_CRCRXE | DSI_PCR_ECCRXE | DSI_PCR_BTAE | - DSI_PCR_ETRXE | DSI_PCR_ETTXE); - DSI->GVCIDR &= - ~DSI_GVCIDR_VCID; // set Virtual Channel ID = 0 for the display - - // Configure the DSI Host LTDC interface - DSI->LVCIDR &= ~3; // Virtual channel ID for LTDC interface traffic - DSI->LCOLCR &= ~DSI_LCOLCR_COLC; - DSI->LCOLCR |= RGB565; // Color coding for the host - DSI->WCFGR &= ~DSI_WCFGR_COLMUX; - DSI->WCFGR |= RGB565 << 1; // Color coding for the wrapper - DSI->LPCR &= ~(DSI_LPCR_DEP | DSI_LPCR_VSP | DSI_LPCR_HSP); - DSI->LPCR |= - (DSI_LPCR_DEP | 0 | - 0); // Polarity of control signals: same of LTDC except for DE - DSI->WCFGR |= DSI_WCFGR_VSPOL; // LTDC halts at VSYNC rising edge - - // Configure the DSI Host for command mode - // Select command mode by setting CMDM and DSIM bits - DSI->MCR |= DSI_MCR_CMDM; - DSI->WCFGR |= DSI_WCFGR_DSIM; - // Configure the maximum allowed size for write memory command - DSI->LCCR &= ~DSI_LCCR_CMDSIZE; - DSI->LCCR |= width; - - DSI->VMCR |= 0x3f << 8; // LP allowed in all video periods - DSI->VMCR &= ~DSI_VMCR_FBTAAE; // Do not request acknowledge at end of - // frame (at this time) - DSI->VMCR |= DSI_VMCR_LPCE; // Allow commands in LP - DSI->VPCR |= width; // Video packet size - DSI->VCCR = 0; // Chunks number to be transmitted through the DSI link - DSI->VNPCR |= 0xFFF; // Size of the null packet - // Timings in lane byte clock cycles - DSI->VLCR |= (hsync + hbp + width + hfp) * clock_ratio; - DSI->VHSACR |= hsync * clock_ratio; - DSI->VHBPCR |= hbp * clock_ratio; - DSI->VVSACR |= vsync; - DSI->VVBPCR |= vbp; - DSI->VVFPCR |= vfp; - DSI->VVACR |= height; - DSI->LPMCR |= (64 << 16); // Low power largest packet size - DSI->LPMCR |= 64; // Low power VACT largest packet size - // Command trasmission only in low power mode - DSI->CMCR |= - (DSI_CMCR_GSW0TX | DSI_CMCR_GSW1TX | DSI_CMCR_GSW2TX | DSI_CMCR_GSR0TX | - DSI_CMCR_GSR1TX | DSI_CMCR_GSR2TX | DSI_CMCR_GLWTX | DSI_CMCR_DSW0TX | - DSI_CMCR_DSW1TX | DSI_CMCR_DSR0TX | DSI_CMCR_DLWTX | DSI_CMCR_MRDPS); - - // Configure the acknowledge request after each packet transmission - DSI->CMCR |= DSI_CMCR_ARE; - - // Enable the D-PHY data lane - DSI->PCTLR |= DSI_PCTLR_DEN; - - // Enable the D-PHY clock lane - DSI->PCTLR |= DSI_PCTLR_CKE; - - // Enable the DSI Host - DSI->CR |= DSI_CR_EN; - - // Enable the DSI wrapper - DSI->WCR |= DSI_WCR_DSIEN; - /* End DSI configuration */ - - // Send DCS commands through the APB generic interface to configure the - // display - /* OTM8009A power up sequence */ - const uint8_t lcdRegData1[] = {0x80, 0x09, 0x01, 0xFF}; - const uint8_t lcdRegData2[] = {0x80, 0x09, 0xFF}; - const uint8_t lcdRegData3[] = {0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10, - 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, - 0x0F, 0x10, 0x0A, 0x01, 0xE1}; - const uint8_t lcdRegData4[] = {0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10, - 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, - 0x0F, 0x10, 0x0A, 0x01, 0xE2}; - const uint8_t lcdRegData5[] = {0x79, 0x79, 0xD8}; - const uint8_t lcdRegData6[] = {0x00, 0x01, 0xB3}; - const uint8_t lcdRegData7[] = {0x85, 0x01, 0x00, 0x84, 0x01, 0x00, 0xCE}; - const uint8_t lcdRegData8[] = {0x18, 0x04, 0x03, 0x39, 0x00, - 0x00, 0x00, 0x18, 0x03, 0x03, - 0x3A, 0x00, 0x00, 0x00, 0xCE}; - const uint8_t lcdRegData9[] = {0x18, 0x02, 0x03, 0x3B, 0x00, - 0x00, 0x00, 0x18, 0x01, 0x03, - 0x3C, 0x00, 0x00, 0x00, 0xCE}; - const uint8_t lcdRegData10[] = {0x01, 0x01, 0x20, 0x20, 0x00, 0x00, - 0x01, 0x02, 0x00, 0x00, 0xCF}; - const uint8_t lcdRegData11[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xCB}; - const uint8_t lcdRegData12[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xCB}; - const uint8_t lcdRegData13[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xCB}; - const uint8_t lcdRegData14[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xCB}; - const uint8_t lcdRegData15[] = {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xCB}; - const uint8_t lcdRegData16[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, - 0x00, 0x00, 0x00, 0xCB}; - const uint8_t lcdRegData17[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xCB}; - const uint8_t lcdRegData18[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xCB}; - const uint8_t lcdRegData19[] = {0x00, 0x26, 0x09, 0x0B, 0x01, 0x25, - 0x00, 0x00, 0x00, 0x00, 0xCC}; - const uint8_t lcdRegData20[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, - 0x0A, 0x0C, 0x02, 0xCC}; - const uint8_t lcdRegData21[] = {0x25, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xCC}; - const uint8_t lcdRegData22[] = {0x00, 0x25, 0x0C, 0x0A, 0x02, 0x26, - 0x00, 0x00, 0x00, 0x00, 0xCC}; - const uint8_t lcdRegData23[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, - 0x0B, 0x09, 0x01, 0xCC}; - const uint8_t lcdRegData24[] = {0x26, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xCC}; - const uint8_t lcdRegData25[] = {0xFF, 0xFF, 0xFF, 0xFF}; - - /* - * CASET value (Column Address Set): X direction LCD GRAM boundaries - * depending on LCD orientation mode PASET value (Page Address Set): Y - * direction LCD GRAM boundaries depending on LCD orientation mode - * - * XS[15:0] = 0x000 = 0, XE[15:0] = 0x31F = 799 for landscape mode: apply to - * CASET YS[15:0] = 0x000 = 0, YE[15:0] = 0x31F = 799 for portrait mode: - * apply to PASET - * - * XS[15:0] = 0x000 = 0, XE[15:0] = 0x1DF = 479 for portrait mode: apply to - * CASET YS[15:0] = 0x000 = 0, YE[15:0] = 0x1DF = 479 for landscape mode: - * apply to PASET - */ + const unsigned int IDF = 4; // must be in the range 1..7 + const unsigned int ODF = 1; // must be in the set {1, 2, 4, 8} + const unsigned int NDIV = 125; // must be in the range 10..125 + const unsigned int F_VCO = + (HSE_VALUE / IDF) * 2 * + NDIV; // 500 MHz - must be between 500 and 1000 MHz + const unsigned int F_PHY_MHz = + (F_VCO / (2 * ODF)) / + 1000000; // 250 MHz - HS clock for D-PHY must be between 80 and 500 MHz + const unsigned int lane_byte_clk = + F_VCO / (2 * ODF * 8); // 31,25 MHz - must be no more than 62,5 MHz + const unsigned int TXECLKDIV = + 2; // must be at least 2 and ensure lane_byte_clk/TXECLKDIV <= 20 MHz + const unsigned int pixel_clock = F_VCO / bpp; // 31,25 MHz + const unsigned int clock_ratio = lane_byte_clk / pixel_clock; + + memset(framebuffer1, 0, height * width * bpp); + + // Reset of screen by active low on GPIO PH7 + typedef Gpio<GPIOH_BASE, 7> reset; + reset::mode(Mode::OUTPUT); + reset::speed(Speed::_100MHz); + reset::low(); + Thread::sleep(20); + reset::high(); + Thread::sleep(10); + + // Enable clock for DSI and LTDC then force their reset + { + FastInterruptDisableLock dLock; + + en::mode(Mode::ALTERNATE); + en::alternateFunction(14); + en::speed(Speed::_100MHz); + dotclk::mode(Mode::ALTERNATE); + dotclk::alternateFunction(14); + dotclk::speed(Speed::_100MHz); + vsync::mode(Mode::ALTERNATE); + vsync::alternateFunction(14); + vsync::speed(Speed::_100MHz); + hsync::mode(Mode::ALTERNATE); + hsync::alternateFunction(14); + hsync::speed(Speed::_100MHz); + r0::mode(Mode::ALTERNATE); + r0::alternateFunction(14); + r0::speed(Speed::_100MHz); + r1::mode(Mode::ALTERNATE); + r1::alternateFunction(14); + r1::speed(Speed::_100MHz); + r2::mode(Mode::ALTERNATE); + r2::alternateFunction(14); + r2::speed(Speed::_100MHz); + r3::mode(Mode::ALTERNATE); + r3::alternateFunction(14); + r3::speed(Speed::_100MHz); + r4::mode(Mode::ALTERNATE); + r4::alternateFunction(14); + r4::speed(Speed::_100MHz); + g0::mode(Mode::ALTERNATE); + g0::alternateFunction(14); + g0::speed(Speed::_100MHz); + g1::mode(Mode::ALTERNATE); + g1::alternateFunction(9); + g1::speed(Speed::_100MHz); + g2::mode(Mode::ALTERNATE); + g2::alternateFunction(9); + g2::speed(Speed::_100MHz); + g3::mode(Mode::ALTERNATE); + g3::alternateFunction(9); + g3::speed(Speed::_100MHz); + g4::mode(Mode::ALTERNATE); + g4::alternateFunction(14); + g4::speed(Speed::_100MHz); + g5::mode(Mode::ALTERNATE); + g5::alternateFunction(14); + g5::speed(Speed::_100MHz); + b0::mode(Mode::ALTERNATE); + b0::alternateFunction(14); + b0::speed(Speed::_100MHz); + b1::mode(Mode::ALTERNATE); + b1::alternateFunction(14); + b1::speed(Speed::_100MHz); + b2::mode(Mode::ALTERNATE); + b2::alternateFunction(9); + b2::speed(Speed::_100MHz); + b3::mode(Mode::ALTERNATE); + b3::alternateFunction(14); + b3::speed(Speed::_100MHz); + b4::mode(Mode::ALTERNATE); + b4::alternateFunction(14); + b4::speed(Speed::_100MHz); + + RCC->APB2ENR |= RCC_APB2ENR_LTDCEN; + RCC_SYNC(); + RCC->APB2ENR |= RCC_APB2ENR_DSIEN; + RCC_SYNC(); + + RCC->APB2RSTR |= RCC_APB2RSTR_LTDCRST; + RCC->APB2RSTR &= ~RCC_APB2RSTR_LTDCRST; + + RCC->APB2RSTR |= RCC_APB2RSTR_DSIRST; + RCC->APB2RSTR &= ~RCC_APB2RSTR_DSIRST; + } - // #if defined MXGUI_ORIENTATION_VERTICAL - // const uint8_t lcdRegData27[] = {0x00, 0x00, 0x03, 0x1F, 0x2B}; - // const uint8_t lcdRegData28[] = {0x00, 0x00, 0x01, 0xDF, 0x2A}; - // #elif defined MXGUI_ORIENTATION_HORIZONTAL - // const uint8_t lcdRegData27[] = {0x00, 0x00, 0x03, 0x1F, 0x2A}; - // const uint8_t lcdRegData28[] = {0x00, 0x00, 0x01, 0xDF, 0x2B}; - // #endif - - const uint8_t ShortRegData1[] = {0x00, 0x00}; - const uint8_t ShortRegData2[] = {0x00, 0x80}; - const uint8_t ShortRegData3[] = {0xC4, 0x30}; - const uint8_t ShortRegData4[] = {0x00, 0x8A}; - const uint8_t ShortRegData5[] = {0xC4, 0x40}; - const uint8_t ShortRegData6[] = {0x00, 0xB1}; - const uint8_t ShortRegData7[] = {0xC5, 0xA9}; - const uint8_t ShortRegData8[] = {0x00, 0x91}; - const uint8_t ShortRegData9[] = {0xC5, 0x34}; - const uint8_t ShortRegData10[] = {0x00, 0xB4}; - const uint8_t ShortRegData11[] = {0xC0, 0x50}; - const uint8_t ShortRegData12[] = {0xD9, 0x4E}; - const uint8_t ShortRegData13[] = {0x00, 0x81}; - const uint8_t ShortRegData14[] = {0xC1, 0x66}; - const uint8_t ShortRegData15[] = {0x00, 0xA1}; - const uint8_t ShortRegData16[] = {0xC1, 0x08}; - const uint8_t ShortRegData17[] = {0x00, 0x92}; - const uint8_t ShortRegData18[] = {0xC5, 0x01}; - const uint8_t ShortRegData19[] = {0x00, 0x95}; - const uint8_t ShortRegData20[] = {0x00, 0x94}; - const uint8_t ShortRegData21[] = {0xC5, 0x33}; - const uint8_t ShortRegData22[] = {0x00, 0xA3}; - const uint8_t ShortRegData23[] = {0xC0, 0x1B}; - const uint8_t ShortRegData24[] = {0x00, 0x82}; - const uint8_t ShortRegData25[] = {0xC5, 0x83}; - const uint8_t ShortRegData26[] = {0xC4, 0x83}; - const uint8_t ShortRegData27[] = {0xC1, 0x0E}; - const uint8_t ShortRegData28[] = {0x00, 0xA6}; - const uint8_t ShortRegData29[] = {0x00, 0xA0}; - const uint8_t ShortRegData30[] = {0x00, 0xB0}; - const uint8_t ShortRegData31[] = {0x00, 0xC0}; - const uint8_t ShortRegData32[] = {0x00, 0xD0}; - const uint8_t ShortRegData33[] = {0x00, 0x90}; - const uint8_t ShortRegData34[] = {0x00, 0xE0}; - const uint8_t ShortRegData35[] = {0x00, 0xF0}; - const uint8_t ShortRegData36[] = {0x11, 0x00}; - const uint8_t ShortRegData37[] = {0x3A, 0x55}; - // const uint8_t ShortRegData38[] = {0x3A, 0x77}; - - // #if defined MXGUI_ORIENTATION_VERTICAL - // const uint8_t ShortRegData39[] = {0x36, 0x00}; - // #elif defined MXGUI_ORIENTATION_HORIZONTAL - // const uint8_t ShortRegData39[] = {0x36, 0x60}; - // #endif - - const uint8_t ShortRegData40[] = { - 0x51, 0xFF}; /* Draupner: Brightness changed from 0x7F */ - const uint8_t ShortRegData41[] = {0x53, 0x2C}; - const uint8_t ShortRegData42[] = {0x55, 0x02}; - const uint8_t ShortRegData43[] = {0x5E, 0xFF}; - const uint8_t ShortRegData44[] = {0x29, 0x00}; - const uint8_t ShortRegData45[] = {0x2C, 0x00}; - const uint8_t ShortRegData46[] = {0xCF, 0x00}; - const uint8_t ShortRegData47[] = {0xC5, 0x66}; - const uint8_t ShortRegData48[] = {0x00, 0xB6}; - const uint8_t ShortRegData49[] = {0xF5, 0x06}; - - sendCmd(0, (uint8_t *)ShortRegData1); - sendCmd(3, (uint8_t *)lcdRegData1); - sendCmd(0, (uint8_t *)ShortRegData2); - sendCmd(2, (uint8_t *)lcdRegData2); - sendCmd(0, (uint8_t *)ShortRegData2); - sendCmd(0, (uint8_t *)ShortRegData3); - Thread::sleep(10); - sendCmd(0, (uint8_t *)ShortRegData4); - sendCmd(0, (uint8_t *)ShortRegData5); - Thread::sleep(10); - sendCmd(0, (uint8_t *)ShortRegData6); - sendCmd(0, (uint8_t *)ShortRegData7); - sendCmd(0, (uint8_t *)ShortRegData8); - sendCmd(0, (uint8_t *)ShortRegData9); - sendCmd(0, (uint8_t *)ShortRegData10); - sendCmd(0, (uint8_t *)ShortRegData11); - sendCmd(0, (uint8_t *)ShortRegData1); - sendCmd(0, (uint8_t *)ShortRegData12); - sendCmd(0, (uint8_t *)ShortRegData13); - sendCmd(0, (uint8_t *)ShortRegData14); - sendCmd(0, (uint8_t *)ShortRegData15); - sendCmd(0, (uint8_t *)ShortRegData16); - sendCmd(0, (uint8_t *)ShortRegData17); - sendCmd(0, (uint8_t *)ShortRegData18); - sendCmd(0, (uint8_t *)ShortRegData19); - sendCmd(0, (uint8_t *)ShortRegData9); - sendCmd(0, (uint8_t *)ShortRegData1); - sendCmd(2, (uint8_t *)lcdRegData5); - sendCmd(0, (uint8_t *)ShortRegData20); - sendCmd(0, (uint8_t *)ShortRegData21); - sendCmd(0, (uint8_t *)ShortRegData22); - sendCmd(0, (uint8_t *)ShortRegData23); - sendCmd(0, (uint8_t *)ShortRegData24); - sendCmd(0, (uint8_t *)ShortRegData25); - sendCmd(0, (uint8_t *)ShortRegData13); - sendCmd(0, (uint8_t *)ShortRegData26); - sendCmd(0, (uint8_t *)ShortRegData15); - sendCmd(0, (uint8_t *)ShortRegData27); - sendCmd(0, (uint8_t *)ShortRegData28); - sendCmd(2, (uint8_t *)lcdRegData6); - sendCmd(0, (uint8_t *)ShortRegData2); - sendCmd(6, (uint8_t *)lcdRegData7); - sendCmd(0, (uint8_t *)ShortRegData29); - sendCmd(14, (uint8_t *)lcdRegData8); - sendCmd(0, (uint8_t *)ShortRegData30); - sendCmd(14, (uint8_t *)lcdRegData9); - sendCmd(0, (uint8_t *)ShortRegData31); - sendCmd(10, (uint8_t *)lcdRegData10); - sendCmd(0, (uint8_t *)ShortRegData32); - sendCmd(0, (uint8_t *)ShortRegData46); - sendCmd(0, (uint8_t *)ShortRegData2); - sendCmd(10, (uint8_t *)lcdRegData11); - sendCmd(0, (uint8_t *)ShortRegData33); - sendCmd(15, (uint8_t *)lcdRegData12); - sendCmd(0, (uint8_t *)ShortRegData29); - sendCmd(15, (uint8_t *)lcdRegData13); - sendCmd(0, (uint8_t *)ShortRegData30); - sendCmd(10, (uint8_t *)lcdRegData14); - sendCmd(0, (uint8_t *)ShortRegData31); - sendCmd(15, (uint8_t *)lcdRegData15); - sendCmd(0, (uint8_t *)ShortRegData32); - sendCmd(15, (uint8_t *)lcdRegData16); - sendCmd(0, (uint8_t *)ShortRegData34); - sendCmd(10, (uint8_t *)lcdRegData17); - sendCmd(0, (uint8_t *)ShortRegData35); - sendCmd(10, (uint8_t *)lcdRegData18); - sendCmd(0, (uint8_t *)ShortRegData2); - sendCmd(10, (uint8_t *)lcdRegData19); - sendCmd(0, (uint8_t *)ShortRegData33); - sendCmd(15, (uint8_t *)lcdRegData20); - sendCmd(0, (uint8_t *)ShortRegData29); - sendCmd(15, (uint8_t *)lcdRegData21); - sendCmd(0, (uint8_t *)ShortRegData30); - sendCmd(10, (uint8_t *)lcdRegData22); - sendCmd(0, (uint8_t *)ShortRegData31); - sendCmd(15, (uint8_t *)lcdRegData23); - sendCmd(0, (uint8_t *)ShortRegData32); - sendCmd(15, (uint8_t *)lcdRegData24); - sendCmd(0, (uint8_t *)ShortRegData13); - sendCmd(0, (uint8_t *)ShortRegData47); - sendCmd(0, (uint8_t *)ShortRegData48); - sendCmd(0, (uint8_t *)ShortRegData49); - sendCmd(0, (uint8_t *)ShortRegData1); - sendCmd(3, (uint8_t *)lcdRegData25); - sendCmd(0, (uint8_t *)ShortRegData1); - sendCmd(0, (uint8_t *)ShortRegData1); - sendCmd(16, (uint8_t *)lcdRegData3); - sendCmd(0, (uint8_t *)ShortRegData1); - sendCmd(16, (uint8_t *)lcdRegData4); - sendCmd(0, (uint8_t *)ShortRegData36); - Thread::sleep(120); - - /* Set Pixel color format to RGB565 */ - sendCmd(0, (uint8_t *)ShortRegData37); - /* Set Pixel color format to RGB888 */ - // sendCmd(0, (uint8_t *)ShortRegData38); + // Configure PLLSAI for LTDC, turn it ON and wait for its lock + { + FastInterruptDisableLock dLock; + + // LTDC clock depends on PLL_M which is fixed at boot with value 8 + // It also depends on PLLSAI which can be freely configured + const unsigned int PLLSAI_N = 384; + const unsigned int PLLSAI_R = 7; + // const unsigned int PLLSAI_DIVR = 0; + + // Input VCO Frequency = HSE_VALUE/PPL_M must be between 1 and 2 MHz, so + // 8/8 = 1 MHz N must be in the range 50..432 and ensure a frequency + // between 100 and 432 MHz if N = 384 then 1 MHz * 384 = 384 MHz R must + // be in the range 2..7, we choose R = 7 so 384/7 = 54,857 MHz and then + // we divide it by 2 (setting DIVR to 0) to obtain 27,428 Mhz + + // Read PLLSAI_P and PLLSAI_Q values from PLLSAICFGR register + uint32_t PLLSAI_P = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIP) >> 16); + uint32_t PLLSAI_Q = ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> 24); + // PLLSAI_VCO_Input = PLL_SOURCE/PLL_M + // PLLSAI_VCO_Output = PLLSAI_VCO_Input * PLLSAI_N + // LTDC_CLK(first level) = PLLSAI_VCO_Output/PLLSAI_R + RCC->PLLSAICFGR = (PLLSAI_N << 6) | (PLLSAI_P << 16) | + (PLLSAI_Q << 24) | (PLLSAI_R << 28); + // LTDC_CLK = LTDC_CLK(first level)/PLLSAI_DIVR + RCC->DCKCFGR = RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR; + + RCC->CR |= RCC_CR_PLLSAION; + } + while ((RCC->CR & RCC_CR_PLLSAIRDY) == 0) + ; + + /* Start LTDC configuration */ + // Configure timings + LTDC->SSCR = (hsync - 1) << 16 | (vsync - 1); + LTDC->BPCR = (hsync + hbp - 1) << 16 | (vsync + vbp - 1); + LTDC->AWCR = (hsync + hbp + width - 1) << 16 | (vsync + vbp + height - 1); + LTDC->TWCR = (hsync + hbp + width + hfp - 1) << 16 | + (vsync + vbp + height + vfp - 1); + + // Configure polarities (everything active high except data enabled) + LTDC->GCR |= + (LTDC_GCR_HSPOL | LTDC_GCR_VSPOL | LTDC_GCR_DEPOL | LTDC_GCR_PCPOL); + LTDC->GCR &= ~LTDC_GCR_DEPOL; + + // Configure background color + LTDC->BCCR = 0; + + // Configure the layer + // Horizontal start and stop position + LTDC_Layer1->WHPCR &= ~(LTDC_LxWHPCR_WHSTPOS | LTDC_LxWHPCR_WHSPPOS); + LTDC_Layer1->WHPCR = ((hsync + hbp + width - 1) << 16) | (hsync + hbp); + // Vertical start and stop position + LTDC_Layer1->WVPCR &= ~(LTDC_LxWVPCR_WVSTPOS | LTDC_LxWVPCR_WVSPPOS); + LTDC_Layer1->WVPCR = ((vsync + vbp + height - 1) << 16) | (vsync + vbp); + // Pixel format + LTDC_Layer1->PFCR &= ~(LTDC_LxPFCR_PF); + LTDC_Layer1->PFCR |= RGB565; + // Color frame buffer start address + LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD); + LTDC_Layer1->CFBAR = reinterpret_cast<unsigned int>(framebuffer1); + // Color frame buffer pitch in byte (multiply by 2 for RGB565) + LTDC_Layer1->CFBLR &= ~(LTDC_LxCFBLR_CFBP | LTDC_LxCFBLR_CFBLL); + LTDC_Layer1->CFBLR = (width * 2) << 16 | (width * 2 + 3); + // Frame buffer line number + LTDC_Layer1->CFBLNR &= ~(LTDC_LxCFBLNR_CFBLNBR); + LTDC_Layer1->CFBLNR = height; + // Default color values (black with no alpha) + LTDC_Layer1->DCCR &= ~(LTDC_LxDCCR_DCBLUE | LTDC_LxDCCR_DCGREEN | + LTDC_LxDCCR_DCRED | LTDC_LxDCCR_DCALPHA); + LTDC_Layer1->DCCR = 0; + // Specifies the constant alpha value + LTDC_Layer1->CACR &= ~(LTDC_LxCACR_CONSTA); + LTDC_Layer1->CACR = 255; + // Blending factors (constant alpha) + LTDC_Layer1->BFCR &= ~(LTDC_LxBFCR_BF2 | LTDC_LxBFCR_BF1); + LTDC_Layer1->BFCR = (0x400 | 0x5); + // Enable layer + LTDC_Layer1->CR |= LTDC_LxCR_LEN; + + // If needed enable dithering and color keying + LTDC_Layer1->CKCR = 0; + + // Reload shadow registers + LTDC->SRCR |= LTDC_SRCR_IMR; + + // Finally enable the display + LTDC->GCR |= LTDC_GCR_LTDCEN; + /* End LTDC configuration */ + + /* Start DSI configuration */ + // Turn on the DSI regulator and wait for the regulator ready + DSI->WRPCR |= DSI_WRPCR_REGEN; + while ((DSI->WISR & DSI_WISR_RRS) == 0) + ; + + // Configure the DSI PLL, turn it ON and wait for its lock + // F_VCO = (HSE_VALUE / IDF) * 2 * NDIV + // Lane_Byte_CLK = F_VCO / (2 * ODF * 8) + // F_VCO must be in the range from 500 MHz to 1 GHz + // To obtain 500 Mbit/s rate, Lane_Byte_CLK must be 31,25 MHz + // Since HSE_VALUE = 8 MHz this is possible with NDIV = 125, IDF = 4, ODF = + // 1 + DSI->WRPCR &= ~(DSI_WRPCR_PLL_NDIV | DSI_WRPCR_PLL_IDF | DSI_WRPCR_PLL_ODF); + DSI->WRPCR |= ((NDIV << 2) | (IDF << 11) | (ODF << 16)); + DSI->WRPCR |= DSI_WRPCR_PLLEN; + while ((DSI->WISR & DSI_WISR_PLLLS) == 0) + ; + + // Configure the D-PHY parameters + // Calculate the bit period in high-speed mode in unit of 0.25 ns (UIX4) + // The equation is: UIX4 = IntegerPart( (1000/F_PHY_MHz) * 4 ) + // Where: F_PHY_MHz = (NDIV * HSE_MHz) / (IDF * ODF) + DSI->WPCR[0] &= ~DSI_WPCR0_UIX4; + DSI->WPCR[0] |= (1000 / F_PHY_MHz) * 4; + // Disable all error interrupts and reset the Error Mask + DSI->IER[0] = 0; + DSI->IER[1] = 0; + // Configure the number of active data lanes (just one out of two for 16 + // bpp) + DSI->PCONFR &= ~DSI_PCONFR_NL; + DSI->PCONFR |= 1; + // Set automatic clock lane control + DSI->CLCR |= (DSI_CLCR_DPCC | DSI_CLCR_ACR); + // Time for LP/HS and HS/LP transitions for both clock lane and data lanes + DSI->CLTCR |= (40 << 16) // HS to LP + | (40 << 0); // LP to HS + DSI->DLTCR |= (20 << 24) // HS to LP + | (20 << 16); // HS to LP + // Stop wait time (don't know how much should it be, random high number in 8 + // bit) + DSI->PCONFR &= ~DSI_PCONFR_SW_TIME; + DSI->PCONFR |= (100 << 8); + + // Configure the DSI Host timing + // DSI->CCR |= (... << 8); // timeout clock configuration non dice nulla... + // Configure clock speed for low-power mode + DSI->CCR &= ~DSI_CCR_TXECKDIV; + DSI->CCR |= TXECLKDIV; + + // Configure the DSI Host flow control and DBI interface + DSI->PCR &= ~(DSI_PCR_CRCRXE | DSI_PCR_ECCRXE | DSI_PCR_BTAE | + DSI_PCR_ETRXE | DSI_PCR_ETTXE); + DSI->GVCIDR &= + ~DSI_GVCIDR_VCID; // set Virtual Channel ID = 0 for the display + + // Configure the DSI Host LTDC interface + DSI->LVCIDR &= ~3; // Virtual channel ID for LTDC interface traffic + DSI->LCOLCR &= ~DSI_LCOLCR_COLC; + DSI->LCOLCR |= RGB565; // Color coding for the host + DSI->WCFGR &= ~DSI_WCFGR_COLMUX; + DSI->WCFGR |= RGB565 << 1; // Color coding for the wrapper + DSI->LPCR &= ~(DSI_LPCR_DEP | DSI_LPCR_VSP | DSI_LPCR_HSP); + DSI->LPCR |= + (DSI_LPCR_DEP | 0 | + 0); // Polarity of control signals: same of LTDC except for DE + DSI->WCFGR |= DSI_WCFGR_VSPOL; // LTDC halts at VSYNC rising edge + + // Configure the DSI Host for command mode + // Select command mode by setting CMDM and DSIM bits + DSI->MCR |= DSI_MCR_CMDM; + DSI->WCFGR |= DSI_WCFGR_DSIM; + // Configure the maximum allowed size for write memory command + DSI->LCCR &= ~DSI_LCCR_CMDSIZE; + DSI->LCCR |= width; + + DSI->VMCR |= 0x3f << 8; // LP allowed in all video periods + DSI->VMCR &= ~DSI_VMCR_FBTAAE; // Do not request acknowledge at end of + // frame (at this time) + DSI->VMCR |= DSI_VMCR_LPCE; // Allow commands in LP + DSI->VPCR |= width; // Video packet size + DSI->VCCR = 0; // Chunks number to be transmitted through the DSI link + DSI->VNPCR |= 0xFFF; // Size of the null packet + // Timings in lane byte clock cycles + DSI->VLCR |= (hsync + hbp + width + hfp) * clock_ratio; + DSI->VHSACR |= hsync * clock_ratio; + DSI->VHBPCR |= hbp * clock_ratio; + DSI->VVSACR |= vsync; + DSI->VVBPCR |= vbp; + DSI->VVFPCR |= vfp; + DSI->VVACR |= height; + DSI->LPMCR |= (64 << 16); // Low power largest packet size + DSI->LPMCR |= 64; // Low power VACT largest packet size + // Command trasmission only in low power mode + DSI->CMCR |= + (DSI_CMCR_GSW0TX | DSI_CMCR_GSW1TX | DSI_CMCR_GSW2TX | DSI_CMCR_GSR0TX | + DSI_CMCR_GSR1TX | DSI_CMCR_GSR2TX | DSI_CMCR_GLWTX | DSI_CMCR_DSW0TX | + DSI_CMCR_DSW1TX | DSI_CMCR_DSR0TX | DSI_CMCR_DLWTX | DSI_CMCR_MRDPS); + + // Configure the acknowledge request after each packet transmission + DSI->CMCR |= DSI_CMCR_ARE; + + // Enable the D-PHY data lane + DSI->PCTLR |= DSI_PCTLR_DEN; + + // Enable the D-PHY clock lane + DSI->PCTLR |= DSI_PCTLR_CKE; + + // Enable the DSI Host + DSI->CR |= DSI_CR_EN; + + // Enable the DSI wrapper + DSI->WCR |= DSI_WCR_DSIEN; + /* End DSI configuration */ + + // Send DCS commands through the APB generic interface to configure the + // display + /* OTM8009A power up sequence */ + const uint8_t lcdRegData1[] = {0x80, 0x09, 0x01, 0xFF}; + const uint8_t lcdRegData2[] = {0x80, 0x09, 0xFF}; + const uint8_t lcdRegData3[] = {0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10, + 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, + 0x0F, 0x10, 0x0A, 0x01, 0xE1}; + const uint8_t lcdRegData4[] = {0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10, + 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, + 0x0F, 0x10, 0x0A, 0x01, 0xE2}; + const uint8_t lcdRegData5[] = {0x79, 0x79, 0xD8}; + const uint8_t lcdRegData6[] = {0x00, 0x01, 0xB3}; + const uint8_t lcdRegData7[] = {0x85, 0x01, 0x00, 0x84, 0x01, 0x00, 0xCE}; + const uint8_t lcdRegData8[] = {0x18, 0x04, 0x03, 0x39, 0x00, + 0x00, 0x00, 0x18, 0x03, 0x03, + 0x3A, 0x00, 0x00, 0x00, 0xCE}; + const uint8_t lcdRegData9[] = {0x18, 0x02, 0x03, 0x3B, 0x00, + 0x00, 0x00, 0x18, 0x01, 0x03, + 0x3C, 0x00, 0x00, 0x00, 0xCE}; + const uint8_t lcdRegData10[] = {0x01, 0x01, 0x20, 0x20, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x00, 0xCF}; + const uint8_t lcdRegData11[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xCB}; + const uint8_t lcdRegData12[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xCB}; + const uint8_t lcdRegData13[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xCB}; + const uint8_t lcdRegData14[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xCB}; + const uint8_t lcdRegData15[] = {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xCB}; + const uint8_t lcdRegData16[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0xCB}; + const uint8_t lcdRegData17[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xCB}; + const uint8_t lcdRegData18[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xCB}; + const uint8_t lcdRegData19[] = {0x00, 0x26, 0x09, 0x0B, 0x01, 0x25, + 0x00, 0x00, 0x00, 0x00, 0xCC}; + const uint8_t lcdRegData20[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, + 0x0A, 0x0C, 0x02, 0xCC}; + const uint8_t lcdRegData21[] = {0x25, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xCC}; + const uint8_t lcdRegData22[] = {0x00, 0x25, 0x0C, 0x0A, 0x02, 0x26, + 0x00, 0x00, 0x00, 0x00, 0xCC}; + const uint8_t lcdRegData23[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, + 0x0B, 0x09, 0x01, 0xCC}; + const uint8_t lcdRegData24[] = {0x26, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xCC}; + const uint8_t lcdRegData25[] = {0xFF, 0xFF, 0xFF, 0xFF}; + + /* + * CASET value (Column Address Set): X direction LCD GRAM boundaries + * depending on LCD orientation mode PASET value (Page Address Set): Y + * direction LCD GRAM boundaries depending on LCD orientation mode + * + * XS[15:0] = 0x000 = 0, XE[15:0] = 0x31F = 799 for landscape mode: apply to + * CASET YS[15:0] = 0x000 = 0, YE[15:0] = 0x31F = 799 for portrait mode: + * apply to PASET + * + * XS[15:0] = 0x000 = 0, XE[15:0] = 0x1DF = 479 for portrait mode: apply to + * CASET YS[15:0] = 0x000 = 0, YE[15:0] = 0x1DF = 479 for landscape mode: + * apply to PASET + */ + + // #if defined MXGUI_ORIENTATION_VERTICAL + // const uint8_t lcdRegData27[] = {0x00, 0x00, 0x03, 0x1F, 0x2B}; + // const uint8_t lcdRegData28[] = {0x00, 0x00, 0x01, 0xDF, 0x2A}; + // #elif defined MXGUI_ORIENTATION_HORIZONTAL + // const uint8_t lcdRegData27[] = {0x00, 0x00, 0x03, 0x1F, 0x2A}; + // const uint8_t lcdRegData28[] = {0x00, 0x00, 0x01, 0xDF, 0x2B}; + // #endif + + const uint8_t ShortRegData1[] = {0x00, 0x00}; + const uint8_t ShortRegData2[] = {0x00, 0x80}; + const uint8_t ShortRegData3[] = {0xC4, 0x30}; + const uint8_t ShortRegData4[] = {0x00, 0x8A}; + const uint8_t ShortRegData5[] = {0xC4, 0x40}; + const uint8_t ShortRegData6[] = {0x00, 0xB1}; + const uint8_t ShortRegData7[] = {0xC5, 0xA9}; + const uint8_t ShortRegData8[] = {0x00, 0x91}; + const uint8_t ShortRegData9[] = {0xC5, 0x34}; + const uint8_t ShortRegData10[] = {0x00, 0xB4}; + const uint8_t ShortRegData11[] = {0xC0, 0x50}; + const uint8_t ShortRegData12[] = {0xD9, 0x4E}; + const uint8_t ShortRegData13[] = {0x00, 0x81}; + const uint8_t ShortRegData14[] = {0xC1, 0x66}; + const uint8_t ShortRegData15[] = {0x00, 0xA1}; + const uint8_t ShortRegData16[] = {0xC1, 0x08}; + const uint8_t ShortRegData17[] = {0x00, 0x92}; + const uint8_t ShortRegData18[] = {0xC5, 0x01}; + const uint8_t ShortRegData19[] = {0x00, 0x95}; + const uint8_t ShortRegData20[] = {0x00, 0x94}; + const uint8_t ShortRegData21[] = {0xC5, 0x33}; + const uint8_t ShortRegData22[] = {0x00, 0xA3}; + const uint8_t ShortRegData23[] = {0xC0, 0x1B}; + const uint8_t ShortRegData24[] = {0x00, 0x82}; + const uint8_t ShortRegData25[] = {0xC5, 0x83}; + const uint8_t ShortRegData26[] = {0xC4, 0x83}; + const uint8_t ShortRegData27[] = {0xC1, 0x0E}; + const uint8_t ShortRegData28[] = {0x00, 0xA6}; + const uint8_t ShortRegData29[] = {0x00, 0xA0}; + const uint8_t ShortRegData30[] = {0x00, 0xB0}; + const uint8_t ShortRegData31[] = {0x00, 0xC0}; + const uint8_t ShortRegData32[] = {0x00, 0xD0}; + const uint8_t ShortRegData33[] = {0x00, 0x90}; + const uint8_t ShortRegData34[] = {0x00, 0xE0}; + const uint8_t ShortRegData35[] = {0x00, 0xF0}; + const uint8_t ShortRegData36[] = {0x11, 0x00}; + const uint8_t ShortRegData37[] = {0x3A, 0x55}; + // const uint8_t ShortRegData38[] = {0x3A, 0x77}; + + // #if defined MXGUI_ORIENTATION_VERTICAL + // const uint8_t ShortRegData39[] = {0x36, 0x00}; + // #elif defined MXGUI_ORIENTATION_HORIZONTAL + // const uint8_t ShortRegData39[] = {0x36, 0x60}; + // #endif + + const uint8_t ShortRegData40[] = { + 0x51, 0xFF}; /* Draupner: Brightness changed from 0x7F */ + const uint8_t ShortRegData41[] = {0x53, 0x2C}; + const uint8_t ShortRegData42[] = {0x55, 0x02}; + const uint8_t ShortRegData43[] = {0x5E, 0xFF}; + const uint8_t ShortRegData44[] = {0x29, 0x00}; + const uint8_t ShortRegData45[] = {0x2C, 0x00}; + const uint8_t ShortRegData46[] = {0xCF, 0x00}; + const uint8_t ShortRegData47[] = {0xC5, 0x66}; + const uint8_t ShortRegData48[] = {0x00, 0xB6}; + const uint8_t ShortRegData49[] = {0xF5, 0x06}; + + sendCmd(0, (uint8_t *)ShortRegData1); + sendCmd(3, (uint8_t *)lcdRegData1); + sendCmd(0, (uint8_t *)ShortRegData2); + sendCmd(2, (uint8_t *)lcdRegData2); + sendCmd(0, (uint8_t *)ShortRegData2); + sendCmd(0, (uint8_t *)ShortRegData3); + Thread::sleep(10); + sendCmd(0, (uint8_t *)ShortRegData4); + sendCmd(0, (uint8_t *)ShortRegData5); + Thread::sleep(10); + sendCmd(0, (uint8_t *)ShortRegData6); + sendCmd(0, (uint8_t *)ShortRegData7); + sendCmd(0, (uint8_t *)ShortRegData8); + sendCmd(0, (uint8_t *)ShortRegData9); + sendCmd(0, (uint8_t *)ShortRegData10); + sendCmd(0, (uint8_t *)ShortRegData11); + sendCmd(0, (uint8_t *)ShortRegData1); + sendCmd(0, (uint8_t *)ShortRegData12); + sendCmd(0, (uint8_t *)ShortRegData13); + sendCmd(0, (uint8_t *)ShortRegData14); + sendCmd(0, (uint8_t *)ShortRegData15); + sendCmd(0, (uint8_t *)ShortRegData16); + sendCmd(0, (uint8_t *)ShortRegData17); + sendCmd(0, (uint8_t *)ShortRegData18); + sendCmd(0, (uint8_t *)ShortRegData19); + sendCmd(0, (uint8_t *)ShortRegData9); + sendCmd(0, (uint8_t *)ShortRegData1); + sendCmd(2, (uint8_t *)lcdRegData5); + sendCmd(0, (uint8_t *)ShortRegData20); + sendCmd(0, (uint8_t *)ShortRegData21); + sendCmd(0, (uint8_t *)ShortRegData22); + sendCmd(0, (uint8_t *)ShortRegData23); + sendCmd(0, (uint8_t *)ShortRegData24); + sendCmd(0, (uint8_t *)ShortRegData25); + sendCmd(0, (uint8_t *)ShortRegData13); + sendCmd(0, (uint8_t *)ShortRegData26); + sendCmd(0, (uint8_t *)ShortRegData15); + sendCmd(0, (uint8_t *)ShortRegData27); + sendCmd(0, (uint8_t *)ShortRegData28); + sendCmd(2, (uint8_t *)lcdRegData6); + sendCmd(0, (uint8_t *)ShortRegData2); + sendCmd(6, (uint8_t *)lcdRegData7); + sendCmd(0, (uint8_t *)ShortRegData29); + sendCmd(14, (uint8_t *)lcdRegData8); + sendCmd(0, (uint8_t *)ShortRegData30); + sendCmd(14, (uint8_t *)lcdRegData9); + sendCmd(0, (uint8_t *)ShortRegData31); + sendCmd(10, (uint8_t *)lcdRegData10); + sendCmd(0, (uint8_t *)ShortRegData32); + sendCmd(0, (uint8_t *)ShortRegData46); + sendCmd(0, (uint8_t *)ShortRegData2); + sendCmd(10, (uint8_t *)lcdRegData11); + sendCmd(0, (uint8_t *)ShortRegData33); + sendCmd(15, (uint8_t *)lcdRegData12); + sendCmd(0, (uint8_t *)ShortRegData29); + sendCmd(15, (uint8_t *)lcdRegData13); + sendCmd(0, (uint8_t *)ShortRegData30); + sendCmd(10, (uint8_t *)lcdRegData14); + sendCmd(0, (uint8_t *)ShortRegData31); + sendCmd(15, (uint8_t *)lcdRegData15); + sendCmd(0, (uint8_t *)ShortRegData32); + sendCmd(15, (uint8_t *)lcdRegData16); + sendCmd(0, (uint8_t *)ShortRegData34); + sendCmd(10, (uint8_t *)lcdRegData17); + sendCmd(0, (uint8_t *)ShortRegData35); + sendCmd(10, (uint8_t *)lcdRegData18); + sendCmd(0, (uint8_t *)ShortRegData2); + sendCmd(10, (uint8_t *)lcdRegData19); + sendCmd(0, (uint8_t *)ShortRegData33); + sendCmd(15, (uint8_t *)lcdRegData20); + sendCmd(0, (uint8_t *)ShortRegData29); + sendCmd(15, (uint8_t *)lcdRegData21); + sendCmd(0, (uint8_t *)ShortRegData30); + sendCmd(10, (uint8_t *)lcdRegData22); + sendCmd(0, (uint8_t *)ShortRegData31); + sendCmd(15, (uint8_t *)lcdRegData23); + sendCmd(0, (uint8_t *)ShortRegData32); + sendCmd(15, (uint8_t *)lcdRegData24); + sendCmd(0, (uint8_t *)ShortRegData13); + sendCmd(0, (uint8_t *)ShortRegData47); + sendCmd(0, (uint8_t *)ShortRegData48); + sendCmd(0, (uint8_t *)ShortRegData49); + sendCmd(0, (uint8_t *)ShortRegData1); + sendCmd(3, (uint8_t *)lcdRegData25); + sendCmd(0, (uint8_t *)ShortRegData1); + sendCmd(0, (uint8_t *)ShortRegData1); + sendCmd(16, (uint8_t *)lcdRegData3); + sendCmd(0, (uint8_t *)ShortRegData1); + sendCmd(16, (uint8_t *)lcdRegData4); + sendCmd(0, (uint8_t *)ShortRegData36); + Thread::sleep(120); + + /* Set Pixel color format to RGB565 */ + sendCmd(0, (uint8_t *)ShortRegData37); + /* Set Pixel color format to RGB888 */ + // sendCmd(0, (uint8_t *)ShortRegData38); #if defined MXGUI_ORIENTATION_HORIZONTAL - /* Send command to configure display in landscape orientation mode. - By default the orientation mode is portrait. */ - sendCmd(0, (uint8_t *)ShortRegData39); - sendCmd(4, (uint8_t *)lcdRegData27); - sendCmd(4, (uint8_t *)lcdRegData28); + /* Send command to configure display in landscape orientation mode. + By default the orientation mode is portrait. */ + sendCmd(0, (uint8_t *)ShortRegData39); + sendCmd(4, (uint8_t *)lcdRegData27); + sendCmd(4, (uint8_t *)lcdRegData28); #endif - sendCmd(0, (uint8_t *)ShortRegData40); - sendCmd(0, (uint8_t *)ShortRegData41); - sendCmd(0, (uint8_t *)ShortRegData42); - sendCmd(0, (uint8_t *)ShortRegData43); - sendCmd(0, (uint8_t *)ShortRegData44); - sendCmd(0, (uint8_t *)ShortRegData1); - sendCmd(0, (uint8_t *)ShortRegData45); - /* End OTM8009A power up sequence */ - - // Disable command trasmission only in low power mode - DSI->CMCR &= ~(DSI_CMCR_GSW0TX | DSI_CMCR_GSW1TX | DSI_CMCR_GSW2TX | - DSI_CMCR_GSR0TX | DSI_CMCR_GSR1TX | DSI_CMCR_GSR2TX | - DSI_CMCR_GLWTX | DSI_CMCR_DSW0TX | DSI_CMCR_DSW1TX | - DSI_CMCR_DSR0TX | DSI_CMCR_DLWTX | DSI_CMCR_MRDPS); - - DSI->PCR &= ~(DSI_PCR_CRCRXE | DSI_PCR_ECCRXE | DSI_PCR_BTAE | - DSI_PCR_ETRXE | DSI_PCR_ETTXE); - DSI->PCR |= DSI_PCR_BTAE; - - // Enable the LTDC - LTDC->GCR |= LTDC_GCR_LTDCEN; - - // Start the LTDC flow through the DSI wrapper (CR.LTDCEN = 1). - // In video mode, the data streaming starts as soon as the LTDC is enabled. - // In adapted command mode, the frame buffer update is launched as soon as - // the CR.LTDCEN bit is set. - DSI->CR |= DSI_CR_EN; - - // Update the display - DSI->WCR |= DSI_WCR_LTDCEN; - - setFont(droid11); - setTextColor(make_pair(Color(0xffff), Color(0x0000))); - clear(black); -} + sendCmd(0, (uint8_t *)ShortRegData40); + sendCmd(0, (uint8_t *)ShortRegData41); + sendCmd(0, (uint8_t *)ShortRegData42); + sendCmd(0, (uint8_t *)ShortRegData43); + sendCmd(0, (uint8_t *)ShortRegData44); + sendCmd(0, (uint8_t *)ShortRegData1); + sendCmd(0, (uint8_t *)ShortRegData45); + /* End OTM8009A power up sequence */ + + // Disable command trasmission only in low power mode + DSI->CMCR &= ~(DSI_CMCR_GSW0TX | DSI_CMCR_GSW1TX | DSI_CMCR_GSW2TX | + DSI_CMCR_GSR0TX | DSI_CMCR_GSR1TX | DSI_CMCR_GSR2TX | + DSI_CMCR_GLWTX | DSI_CMCR_DSW0TX | DSI_CMCR_DSW1TX | + DSI_CMCR_DSR0TX | DSI_CMCR_DLWTX | DSI_CMCR_MRDPS); + + DSI->PCR &= ~(DSI_PCR_CRCRXE | DSI_PCR_ECCRXE | DSI_PCR_BTAE | + DSI_PCR_ETRXE | DSI_PCR_ETTXE); + DSI->PCR |= DSI_PCR_BTAE; + + // Enable the LTDC + LTDC->GCR |= LTDC_GCR_LTDCEN; + + // Start the LTDC flow through the DSI wrapper (CR.LTDCEN = 1). + // In video mode, the data streaming starts as soon as the LTDC is enabled. + // In adapted command mode, the frame buffer update is launched as soon as + // the CR.LTDCEN bit is set. + DSI->CR |= DSI_CR_EN; + + // Update the display + DSI->WCR |= DSI_WCR_LTDCEN; + + setFont(droid11); + setTextColor(make_pair(Color(0xffff), Color(0x0000))); + clear(black); + } -Color DisplayImpl::pixel_iterator::dummy; + Color DisplayImpl::pixel_iterator::dummy; -} // namespace mxgui +} // namespace mxgui -#endif //_BOARD_STM32F469NI_STM32F469I_DISCO +#endif //_BOARD_STM32F469NI_STM32F469I_DISCO diff --git a/mxgui/drivers/display_stm32f4discovery.h b/mxgui/drivers/display_stm32f4discovery.h index cecc4fe52879ae3c3b9de67f817d43451ea88f65..8a722ded7442d410cf3a89d1aeac02f8afb5243f 100644 --- a/mxgui/drivers/display_stm32f4discovery.h +++ b/mxgui/drivers/display_stm32f4discovery.h @@ -28,7 +28,7 @@ #ifndef MXGUI_LIBRARY #error "This is header is private, it can be used only within mxgui." #error "If your code depends on a private header, it IS broken." -#endif // MXGUI_LIBRARY +#endif // MXGUI_LIBRARY #ifndef DISPLAY_STM32F4DISCOVERY_H #define DISPLAY_STM32F4DISCOVERY_H @@ -47,7 +47,8 @@ defined(_BOARD_STM32F429ZI_HRE_TEST_STAND) || \ defined(_BOARD_STM32F429ZI_SKYWARD_PYXIS_AUXILIARY) || \ defined(_BOARD_STM32F429ZI_SKYWARD_PARAFOIL) || \ - defined(_BOARD_STM32F205RC_SKYWARD_CIUTI) + defined(_BOARD_STM32F205RC_SKYWARD_CIUTI) || \ + defined(_BOARD_STM32F429ZI_SKYWARD_RIG) #include <config/mxgui_settings.h> @@ -73,295 +74,295 @@ namespace mxgui #error The ILI9341 driver requires a color depth of 16bit per pixel #endif -class DisplayImpl : public Display -{ -public: - /** - * \return an instance to this class (singleton) - */ - static DisplayImpl& instance(); - - /** - * Turn the display On after it has been turned Off. - * Display initial state is On. - */ - void doTurnOn() override; - - /** - * Turn the display Off. It can be later turned back On. - */ - void doTurnOff() override; - - /** - * Set display brightness. Depending on the underlying driver, - * may do nothing. - * \param brt from 0 to 100 - */ - void doSetBrightness(int brt) override; - - /** - * \return a pair with the display height and width - */ - std::pair<short int, short int> doGetSize() const override; - - /** - * Write text to the display. If text is too long it will be truncated - * \param p point where the upper left corner of the text will be printed - * \param text, text to print. - */ - void write(Point p, const char* text) override; - - /** - * Write part of text to the display - * \param p point of the upper left corner where the text will be drawn. - * Negative coordinates are allowed, as long as the clipped view has - * positive or zero coordinates - * \param a Upper left corner of clipping rectangle - * \param b Lower right corner of clipping rectangle - * \param text text to write - */ - void clippedWrite(Point p, Point a, Point b, const char* text) override; - - /** - * Clear the Display. The screen will be filled with the desired color - * \param color fill color - */ - void clear(Color color) override; - - /** - * Clear an area of the screen - * \param p1 upper left corner of area to clear - * \param p2 lower right corner of area to clear - * \param color fill color - */ - void clear(Point p1, Point p2, Color color) override; - - /** - * This backend does not require it, so it is a blank. - */ - void beginPixel() override; - - /** - * Draw a pixel with desired color. You have to call beginPixel() once - * before calling setPixel() - * \param p point where to draw pixel - * \param color pixel color - */ - void setPixel(Point p, Color color) override; - - /** - * Draw a line between point a and point b, with color c - * \param a first point - * \param b second point - * \param c line color - */ - void line(Point a, Point b, Color color) override; - - /** - * Draw an horizontal line on screen. - * Instead of line(), this member function takes an array of colors to be - * able to individually set pixel colors of a line. - * \param p starting point of the line - * \param colors an array of pixel colors whoase size must be b.x()-a.x()+1 - * \param length length of colors array. - * p.x()+length must be <= display.width() - */ - void scanLine(Point p, const Color* colors, unsigned short length) override; - - /** - * \return a buffer of length equal to this->getWidth() that can be used to - * render a scanline. - */ - Color* getScanLineBuffer() override; - - /** - * Draw the content of the last getScanLineBuffer() on an horizontal line - * on the screen. - * \param p starting point of the line - * \param length length of colors array. - * p.x()+length must be <= display.width() - */ - void scanLineBuffer(Point p, unsigned short length) override; - - /** - * Draw an image on the screen - * \param p point of the upper left corner where the image will be drawn - * \param i image to draw - */ - void drawImage(Point p, const ImageBase& img) override; - - /** - * Draw part of an image on the screen - * \param p point of the upper left corner where the image will be drawn. - * Negative coordinates are allowed, as long as the clipped view has - * positive or zero coordinates - * \param a Upper left corner of clipping rectangle - * \param b Lower right corner of clipping rectangle - * \param i Image to draw - */ - void clippedDrawImage(Point p, Point a, Point b, - const ImageBase& img) override; - - /** - * Draw a rectangle (not filled) with the desired color - * \param a upper left corner of the rectangle - * \param b lower right corner of the rectangle - * \param c color of the line - */ - void drawRectangle(Point a, Point b, Color c) override; - - /** - * Pixel iterator. A pixel iterator is an output iterator that allows to - * define a window on the display and write to its pixels. - */ - class pixel_iterator + class DisplayImpl : public Display { public: /** - * Default constructor, results in an invalid iterator. - * Note that since aIncr and sIncr are both zero all the writes will - * happens to the same memory location, but we need a safe - * /dev/null-like location where to write, which is dummy + * \return an instance to this class (singleton) */ - pixel_iterator() - : ctr(0), endCtr(0), aIncr(0), sIncr(0), dataPtr(&dummy) - { - } + static DisplayImpl &instance(); /** - * Set a pixel and move the pointer to the next one - * \param color color to set the current pixel - * \return a reference to this + * Turn the display On after it has been turned Off. + * Display initial state is On. */ - pixel_iterator& operator=(Color color) - { - *dataPtr = color; + void doTurnOn() override; - // This is to move to the adjacent pixel - dataPtr += aIncr; + /** + * Turn the display Off. It can be later turned back On. + */ + void doTurnOff() override; - // This is the step move to the next horizontal/vertical line - if (++ctr >= endCtr) - { - ctr = 0; - dataPtr += sIncr; - } - return *this; - } + /** + * Set display brightness. Depending on the underlying driver, + * may do nothing. + * \param brt from 0 to 100 + */ + void doSetBrightness(int brt) override; /** - * Compare two pixel_iterators for equality. - * They are equal if they point to the same location. + * \return a pair with the display height and width */ - bool operator==(const pixel_iterator& itr) - { - return this->dataPtr == itr.dataPtr; - } + std::pair<short int, short int> doGetSize() const override; /** - * Compare two pixel_iterators for inequality. - * They different if they point to different locations. + * Write text to the display. If text is too long it will be truncated + * \param p point where the upper left corner of the text will be printed + * \param text, text to print. */ - bool operator!=(const pixel_iterator& itr) - { - return this->dataPtr != itr.dataPtr; - } + void write(Point p, const char *text) override; /** - * \return a reference to this. + * Write part of text to the display + * \param p point of the upper left corner where the text will be drawn. + * Negative coordinates are allowed, as long as the clipped view has + * positive or zero coordinates + * \param a Upper left corner of clipping rectangle + * \param b Lower right corner of clipping rectangle + * \param text text to write */ - pixel_iterator& operator*() { return *this; } + void clippedWrite(Point p, Point a, Point b, const char *text) override; /** - * \return a reference to this. Does not increment pixel pointer. + * Clear the Display. The screen will be filled with the desired color + * \param color fill color */ - pixel_iterator& operator++() { return *this; } + void clear(Color color) override; /** - * \return a reference to this. Does not increment pixel pointer. + * Clear an area of the screen + * \param p1 upper left corner of area to clear + * \param p2 lower right corner of area to clear + * \param color fill color */ - pixel_iterator& operator++(int) { return *this; } + void clear(Point p1, Point p2, Color color) override; /** - * Must be called if not all pixels of the required window are going - * to be written. + * This backend does not require it, so it is a blank. */ - void invalidate() {} + void beginPixel() override; + + /** + * Draw a pixel with desired color. You have to call beginPixel() once + * before calling setPixel() + * \param p point where to draw pixel + * \param color pixel color + */ + void setPixel(Point p, Color color) override; + + /** + * Draw a line between point a and point b, with color c + * \param a first point + * \param b second point + * \param c line color + */ + void line(Point a, Point b, Color color) override; + + /** + * Draw an horizontal line on screen. + * Instead of line(), this member function takes an array of colors to be + * able to individually set pixel colors of a line. + * \param p starting point of the line + * \param colors an array of pixel colors whoase size must be b.x()-a.x()+1 + * \param length length of colors array. + * p.x()+length must be <= display.width() + */ + void scanLine(Point p, const Color *colors, unsigned short length) override; + + /** + * \return a buffer of length equal to this->getWidth() that can be used to + * render a scanline. + */ + Color *getScanLineBuffer() override; + + /** + * Draw the content of the last getScanLineBuffer() on an horizontal line + * on the screen. + * \param p starting point of the line + * \param length length of colors array. + * p.x()+length must be <= display.width() + */ + void scanLineBuffer(Point p, unsigned short length) override; + + /** + * Draw an image on the screen + * \param p point of the upper left corner where the image will be drawn + * \param i image to draw + */ + void drawImage(Point p, const ImageBase &img) override; + + /** + * Draw part of an image on the screen + * \param p point of the upper left corner where the image will be drawn. + * Negative coordinates are allowed, as long as the clipped view has + * positive or zero coordinates + * \param a Upper left corner of clipping rectangle + * \param b Lower right corner of clipping rectangle + * \param i Image to draw + */ + void clippedDrawImage(Point p, Point a, Point b, + const ImageBase &img) override; + + /** + * Draw a rectangle (not filled) with the desired color + * \param a upper left corner of the rectangle + * \param b lower right corner of the rectangle + * \param c color of the line + */ + void drawRectangle(Point a, Point b, Color c) override; - private: /** - * Constructor - * \param start Upper left corner of window - * \param end Lower right corner of window - * \param direction Iterator direction - * \param disp Display we're associated + * Pixel iterator. A pixel iterator is an output iterator that allows to + * define a window on the display and write to its pixels. */ - pixel_iterator(Point start, Point end, IteratorDirection direction, - DisplayImpl* disp) - : ctr(0), dataPtr(disp->framebuffer1) + class pixel_iterator { - // Compute the increment in the adjacent direction (aIncr) and in - // the step direction (sIncr) depending on the direction - dataPtr += start.y() * disp->getWidth() + start.x(); - if (direction == RD) + public: + /** + * Default constructor, results in an invalid iterator. + * Note that since aIncr and sIncr are both zero all the writes will + * happens to the same memory location, but we need a safe + * /dev/null-like location where to write, which is dummy + */ + pixel_iterator() + : ctr(0), endCtr(0), aIncr(0), sIncr(0), dataPtr(&dummy) + { + } + + /** + * Set a pixel and move the pointer to the next one + * \param color color to set the current pixel + * \return a reference to this + */ + pixel_iterator &operator=(Color color) + { + *dataPtr = color; + + // This is to move to the adjacent pixel + dataPtr += aIncr; + + // This is the step move to the next horizontal/vertical line + if (++ctr >= endCtr) + { + ctr = 0; + dataPtr += sIncr; + } + return *this; + } + + /** + * Compare two pixel_iterators for equality. + * They are equal if they point to the same location. + */ + bool operator==(const pixel_iterator &itr) + { + return this->dataPtr == itr.dataPtr; + } + + /** + * Compare two pixel_iterators for inequality. + * They different if they point to different locations. + */ + bool operator!=(const pixel_iterator &itr) { - endCtr = end.x() + 1 - start.x(); - aIncr = 1; - sIncr = disp->getWidth() - endCtr; + return this->dataPtr != itr.dataPtr; } - else + + /** + * \return a reference to this. + */ + pixel_iterator &operator*() { return *this; } + + /** + * \return a reference to this. Does not increment pixel pointer. + */ + pixel_iterator &operator++() { return *this; } + + /** + * \return a reference to this. Does not increment pixel pointer. + */ + pixel_iterator &operator++(int) { return *this; } + + /** + * Must be called if not all pixels of the required window are going + * to be written. + */ + void invalidate() {} + + private: + /** + * Constructor + * \param start Upper left corner of window + * \param end Lower right corner of window + * \param direction Iterator direction + * \param disp Display we're associated + */ + pixel_iterator(Point start, Point end, IteratorDirection direction, + DisplayImpl *disp) + : ctr(0), dataPtr(disp->framebuffer1) { - endCtr = end.y() + 1 - start.y(); - aIncr = disp->getWidth(); - sIncr = -aIncr * endCtr + 1; + // Compute the increment in the adjacent direction (aIncr) and in + // the step direction (sIncr) depending on the direction + dataPtr += start.y() * disp->getWidth() + start.x(); + if (direction == RD) + { + endCtr = end.x() + 1 - start.x(); + aIncr = 1; + sIncr = disp->getWidth() - endCtr; + } + else + { + endCtr = end.y() + 1 - start.y(); + aIncr = disp->getWidth(); + sIncr = -aIncr * endCtr + 1; + } } - } - unsigned short ctr; ///< Counter to decide when to step - unsigned short endCtr; ///< When ctr==endCtr apply a step + unsigned short ctr; ///< Counter to decide when to step + unsigned short endCtr; ///< When ctr==endCtr apply a step - short aIncr; ///< Adjacent increment - int sIncr; ///< Step increment - Color* dataPtr; ///< Pointer to framebuffer + short aIncr; ///< Adjacent increment + int sIncr; ///< Step increment + Color *dataPtr; ///< Pointer to framebuffer - static Color dummy; ///< Invalid iterators write here + static Color dummy; ///< Invalid iterators write here - friend class DisplayImpl; // Needs access to ctor - }; + friend class DisplayImpl; // Needs access to ctor + }; + + /** + * Specify a window on screen and return an object that allows to write + * its pixels. + * Note: a call to begin() will invalidate any previous iterator. + * \param p1 upper left corner of window + * \param p2 lower right corner (included) + * \param d increment direction + * \return a pixel iterator + */ + pixel_iterator begin(Point p1, Point p2, IteratorDirection d); + + /** + * \return an iterator which is one past the last pixel in the pixel + * specified by begin. Behaviour is undefined if called before calling + * begin() + */ + pixel_iterator end() const { return last; } + + /** + * Destructor + */ + ~DisplayImpl() override; - /** - * Specify a window on screen and return an object that allows to write - * its pixels. - * Note: a call to begin() will invalidate any previous iterator. - * \param p1 upper left corner of window - * \param p2 lower right corner (included) - * \param d increment direction - * \return a pixel iterator - */ - pixel_iterator begin(Point p1, Point p2, IteratorDirection d); - - /** - * \return an iterator which is one past the last pixel in the pixel - * specified by begin. Behaviour is undefined if called before calling - * begin() - */ - pixel_iterator end() const { return last; } - - /** - * Destructor - */ - ~DisplayImpl() override; - -private: - /** - * Constructor. - * Do not instantiate objects of this type directly from application code. - */ - DisplayImpl(); + private: + /** + * Constructor. + * Do not instantiate objects of this type directly from application code. + */ + DisplayImpl(); #if defined MXGUI_ORIENTATION_VERTICAL - static const short int width = 240; - static const short int height = 320; + static const short int width = 240; + static const short int height = 320; #elif defined MXGUI_ORIENTATION_HORIZONTAL || \ defined MXGUI_ORIENTATION_VERTICAL_MIRRORED || \ defined MXGUI_ORIENTATION_HORIZONTAL_MIRRORED @@ -370,20 +371,20 @@ private: #error No orientation defined #endif - /** - * Pointer to the memory mapped display. - */ - Color* const framebuffer1; - Color* buffer; ///< For scanLineBuffer - pixel_iterator last; ///< Last iterator for end of iteration check - static const unsigned int bpp = sizeof(Color); ///< Bytes per pixel - static const int numPixels = - width * height; ///< Number of pixels of the display -}; + /** + * Pointer to the memory mapped display. + */ + Color *const framebuffer1; + Color *buffer; ///< For scanLineBuffer + pixel_iterator last; ///< Last iterator for end of iteration check + static const unsigned int bpp = sizeof(Color); ///< Bytes per pixel + static const int numPixels = + width * height; ///< Number of pixels of the display + }; -} // namespace mxgui +} // namespace mxgui -#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY +#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY #ifdef _BOARD_STM32F469NI_STM32F469I_DISCO @@ -411,304 +412,304 @@ namespace mxgui #error The OTM8009A driver requires a color depth of 16bit per pixel #endif -class DisplayImpl : public Display -{ -public: - /** - * \return an instance to this class (singleton) - */ - static DisplayImpl& instance(); - - /** - * Turn the display On after it has been turned Off. - * Display initial state is On. - */ - void doTurnOn() override; - - /** - * Turn the display Off. It can be later turned back On. - */ - void doTurnOff() override; - - /** - * Set display brightness. Depending on the underlying driver, - * may do nothing. - * \param brt from 0 to 100 - */ - void doSetBrightness(int brt) override; - - /** - * \return a pair with the display height and width - */ - std::pair<short int, short int> doGetSize() const override; - - /** - * Write text to the display. If text is too long it will be truncated - * \param p point where the upper left corner of the text will be printed - * \param text, text to print. - */ - void write(Point p, const char* text) override; - - /** - * Write part of text to the display - * \param p point of the upper left corner where the text will be drawn. - * Negative coordinates are allowed, as long as the clipped view has - * positive or zero coordinates - * \param a Upper left corner of clipping rectangle - * \param b Lower right corner of clipping rectangle - * \param text text to write - */ - void clippedWrite(Point p, Point a, Point b, const char* text) override; - - /** - * Clear the Display. The screen will be filled with the desired color - * \param color fill color - */ - void clear(Color color) override; - - /** - * Clear an area of the screen - * \param p1 upper left corner of area to clear - * \param p2 lower right corner of area to clear - * \param color fill color - */ - void clear(Point p1, Point p2, Color color) override; - - /** - * This backend does not require it, so it is a blank. - */ - void beginPixel() override; - - /** - * Draw a pixel with desired color. You have to call beginPixel() once - * before calling setPixel() - * \param p point where to draw pixel - * \param color pixel color - */ - void setPixel(Point p, Color color) override; - - /** - * Draw a line between point a and point b, with color c - * \param a first point - * \param b second point - * \param c line color - */ - void line(Point a, Point b, Color color) override; - - /** - * Draw an horizontal line on screen. - * Instead of line(), this member function takes an array of colors to be - * able to individually set pixel colors of a line. - * \param p starting point of the line - * \param colors an array of pixel colors whoase size must be b.x()-a.x()+1 - * \param length length of colors array. - * p.x()+length must be <= display.width() - */ - void scanLine(Point p, const Color* colors, unsigned short length) override; - - /** - * \return a buffer of length equal to this->getWidth() that can be used to - * render a scanline. - */ - Color* getScanLineBuffer() override; - - /** - * Draw the content of the last getScanLineBuffer() on an horizontal line - * on the screen. - * \param p starting point of the line - * \param length length of colors array. - * p.x()+length must be <= display.width() - */ - void scanLineBuffer(Point p, unsigned short length) override; - - /** - * Draw an image on the screen - * \param p point of the upper left corner where the image will be drawn - * \param i image to draw - */ - void drawImage(Point p, const ImageBase& img) override; - - /** - * Draw part of an image on the screen - * \param p point of the upper left corner where the image will be drawn. - * Negative coordinates are allowed, as long as the clipped view has - * positive or zero coordinates - * \param a Upper left corner of clipping rectangle - * \param b Lower right corner of clipping rectangle - * \param i Image to draw - */ - void clippedDrawImage(Point p, Point a, Point b, - const ImageBase& img) override; - - /** - * Draw a rectangle (not filled) with the desired color - * \param a upper left corner of the rectangle - * \param b lower right corner of the rectangle - * \param c color of the line - */ - void drawRectangle(Point a, Point b, Color c) override; - - /** - * Make all changes done to the display since the last call to update() - * visible. This backend requires it. - */ - void update() override; - - /** - * Pixel iterator. A pixel iterator is an output iterator that allows to - * define a window on the display and write to its pixels. - */ - class pixel_iterator + class DisplayImpl : public Display { public: /** - * Default constructor, results in an invalid iterator. - * Note that since aIncr and sIncr are both zero all the writes will - * happens to the same memory location, but we need a safe - * /dev/null-like location where to write, which is dummy + * \return an instance to this class (singleton) */ - pixel_iterator() - : ctr(0), endCtr(0), aIncr(0), sIncr(0), dataPtr(&dummy) - { - } + static DisplayImpl &instance(); /** - * Set a pixel and move the pointer to the next one - * \param color color to set the current pixel - * \return a reference to this + * Turn the display On after it has been turned Off. + * Display initial state is On. */ - pixel_iterator& operator=(Color color) - { - *dataPtr = color; + void doTurnOn() override; - // This is to move to the adjacent pixel - dataPtr += aIncr; + /** + * Turn the display Off. It can be later turned back On. + */ + void doTurnOff() override; - // This is the step move to the next horizontal/vertical line - if (++ctr >= endCtr) - { - ctr = 0; - dataPtr += sIncr; - } - return *this; - } + /** + * Set display brightness. Depending on the underlying driver, + * may do nothing. + * \param brt from 0 to 100 + */ + void doSetBrightness(int brt) override; /** - * Compare two pixel_iterators for equality. - * They are equal if they point to the same location. + * \return a pair with the display height and width */ - bool operator==(const pixel_iterator& itr) - { - return this->dataPtr == itr.dataPtr; - } + std::pair<short int, short int> doGetSize() const override; /** - * Compare two pixel_iterators for inequality. - * They different if they point to different locations. + * Write text to the display. If text is too long it will be truncated + * \param p point where the upper left corner of the text will be printed + * \param text, text to print. */ - bool operator!=(const pixel_iterator& itr) - { - return this->dataPtr != itr.dataPtr; - } + void write(Point p, const char *text) override; /** - * \return a reference to this. + * Write part of text to the display + * \param p point of the upper left corner where the text will be drawn. + * Negative coordinates are allowed, as long as the clipped view has + * positive or zero coordinates + * \param a Upper left corner of clipping rectangle + * \param b Lower right corner of clipping rectangle + * \param text text to write */ - pixel_iterator& operator*() { return *this; } + void clippedWrite(Point p, Point a, Point b, const char *text) override; /** - * \return a reference to this. Does not increment pixel pointer. + * Clear the Display. The screen will be filled with the desired color + * \param color fill color */ - pixel_iterator& operator++() { return *this; } + void clear(Color color) override; /** - * \return a reference to this. Does not increment pixel pointer. + * Clear an area of the screen + * \param p1 upper left corner of area to clear + * \param p2 lower right corner of area to clear + * \param color fill color */ - pixel_iterator& operator++(int) { return *this; } + void clear(Point p1, Point p2, Color color) override; /** - * Must be called if not all pixels of the required window are going - * to be written. + * This backend does not require it, so it is a blank. */ - void invalidate() {} + void beginPixel() override; + + /** + * Draw a pixel with desired color. You have to call beginPixel() once + * before calling setPixel() + * \param p point where to draw pixel + * \param color pixel color + */ + void setPixel(Point p, Color color) override; + + /** + * Draw a line between point a and point b, with color c + * \param a first point + * \param b second point + * \param c line color + */ + void line(Point a, Point b, Color color) override; - private: /** - * Constructor - * \param start Upper left corner of window - * \param end Lower right corner of window - * \param direction Iterator direction - * \param disp Display we're associated + * Draw an horizontal line on screen. + * Instead of line(), this member function takes an array of colors to be + * able to individually set pixel colors of a line. + * \param p starting point of the line + * \param colors an array of pixel colors whoase size must be b.x()-a.x()+1 + * \param length length of colors array. + * p.x()+length must be <= display.width() */ - pixel_iterator(Point start, Point end, IteratorDirection direction, - DisplayImpl* disp) - : ctr(0), dataPtr(disp->framebuffer1) + void scanLine(Point p, const Color *colors, unsigned short length) override; + + /** + * \return a buffer of length equal to this->getWidth() that can be used to + * render a scanline. + */ + Color *getScanLineBuffer() override; + + /** + * Draw the content of the last getScanLineBuffer() on an horizontal line + * on the screen. + * \param p starting point of the line + * \param length length of colors array. + * p.x()+length must be <= display.width() + */ + void scanLineBuffer(Point p, unsigned short length) override; + + /** + * Draw an image on the screen + * \param p point of the upper left corner where the image will be drawn + * \param i image to draw + */ + void drawImage(Point p, const ImageBase &img) override; + + /** + * Draw part of an image on the screen + * \param p point of the upper left corner where the image will be drawn. + * Negative coordinates are allowed, as long as the clipped view has + * positive or zero coordinates + * \param a Upper left corner of clipping rectangle + * \param b Lower right corner of clipping rectangle + * \param i Image to draw + */ + void clippedDrawImage(Point p, Point a, Point b, + const ImageBase &img) override; + + /** + * Draw a rectangle (not filled) with the desired color + * \param a upper left corner of the rectangle + * \param b lower right corner of the rectangle + * \param c color of the line + */ + void drawRectangle(Point a, Point b, Color c) override; + + /** + * Make all changes done to the display since the last call to update() + * visible. This backend requires it. + */ + void update() override; + + /** + * Pixel iterator. A pixel iterator is an output iterator that allows to + * define a window on the display and write to its pixels. + */ + class pixel_iterator { - // Compute the increment in the adjacent direction (aIncr) and in - // the step direction (sIncr) depending on the direction - dataPtr += start.y() * disp->getWidth() + start.x(); - if (direction == RD) + public: + /** + * Default constructor, results in an invalid iterator. + * Note that since aIncr and sIncr are both zero all the writes will + * happens to the same memory location, but we need a safe + * /dev/null-like location where to write, which is dummy + */ + pixel_iterator() + : ctr(0), endCtr(0), aIncr(0), sIncr(0), dataPtr(&dummy) + { + } + + /** + * Set a pixel and move the pointer to the next one + * \param color color to set the current pixel + * \return a reference to this + */ + pixel_iterator &operator=(Color color) { - endCtr = end.x() + 1 - start.x(); - aIncr = 1; - sIncr = disp->getWidth() - endCtr; + *dataPtr = color; + + // This is to move to the adjacent pixel + dataPtr += aIncr; + + // This is the step move to the next horizontal/vertical line + if (++ctr >= endCtr) + { + ctr = 0; + dataPtr += sIncr; + } + return *this; } - else + + /** + * Compare two pixel_iterators for equality. + * They are equal if they point to the same location. + */ + bool operator==(const pixel_iterator &itr) + { + return this->dataPtr == itr.dataPtr; + } + + /** + * Compare two pixel_iterators for inequality. + * They different if they point to different locations. + */ + bool operator!=(const pixel_iterator &itr) { - endCtr = end.y() + 1 - start.y(); - aIncr = disp->getWidth(); - sIncr = -aIncr * endCtr + 1; + return this->dataPtr != itr.dataPtr; } - } - unsigned short ctr; ///< Counter to decide when to step - unsigned short endCtr; ///< When ctr==endCtr apply a step + /** + * \return a reference to this. + */ + pixel_iterator &operator*() { return *this; } + + /** + * \return a reference to this. Does not increment pixel pointer. + */ + pixel_iterator &operator++() { return *this; } + + /** + * \return a reference to this. Does not increment pixel pointer. + */ + pixel_iterator &operator++(int) { return *this; } + + /** + * Must be called if not all pixels of the required window are going + * to be written. + */ + void invalidate() {} + + private: + /** + * Constructor + * \param start Upper left corner of window + * \param end Lower right corner of window + * \param direction Iterator direction + * \param disp Display we're associated + */ + pixel_iterator(Point start, Point end, IteratorDirection direction, + DisplayImpl *disp) + : ctr(0), dataPtr(disp->framebuffer1) + { + // Compute the increment in the adjacent direction (aIncr) and in + // the step direction (sIncr) depending on the direction + dataPtr += start.y() * disp->getWidth() + start.x(); + if (direction == RD) + { + endCtr = end.x() + 1 - start.x(); + aIncr = 1; + sIncr = disp->getWidth() - endCtr; + } + else + { + endCtr = end.y() + 1 - start.y(); + aIncr = disp->getWidth(); + sIncr = -aIncr * endCtr + 1; + } + } - short aIncr; ///< Adjacent increment - int sIncr; ///< Step increment - Color* dataPtr; ///< Pointer to framebuffer + unsigned short ctr; ///< Counter to decide when to step + unsigned short endCtr; ///< When ctr==endCtr apply a step - static Color dummy; ///< Invalid iterators write here + short aIncr; ///< Adjacent increment + int sIncr; ///< Step increment + Color *dataPtr; ///< Pointer to framebuffer - friend class DisplayImpl; // Needs access to ctor - }; + static Color dummy; ///< Invalid iterators write here - /** - * Specify a window on screen and return an object that allows to write - * its pixels. - * Note: a call to begin() will invalidate any previous iterator. - * \param p1 upper left corner of window - * \param p2 lower right corner (included) - * \param d increment direction - * \return a pixel iterator - */ - pixel_iterator begin(Point p1, Point p2, IteratorDirection d); - - /** - * \return an iterator which is one past the last pixel in the pixel - * specified by begin. Behaviour is undefined if called before calling - * begin() - */ - pixel_iterator end() const { return last; } - - /** - * Destructor - */ - ~DisplayImpl() override; - -private: - /** - * Constructor. - * Do not instantiate objects of this type directly from application code. - */ - DisplayImpl(); + friend class DisplayImpl; // Needs access to ctor + }; + + /** + * Specify a window on screen and return an object that allows to write + * its pixels. + * Note: a call to begin() will invalidate any previous iterator. + * \param p1 upper left corner of window + * \param p2 lower right corner (included) + * \param d increment direction + * \return a pixel iterator + */ + pixel_iterator begin(Point p1, Point p2, IteratorDirection d); + + /** + * \return an iterator which is one past the last pixel in the pixel + * specified by begin. Behaviour is undefined if called before calling + * begin() + */ + pixel_iterator end() const { return last; } + + /** + * Destructor + */ + ~DisplayImpl() override; + + private: + /** + * Constructor. + * Do not instantiate objects of this type directly from application code. + */ + DisplayImpl(); #if defined MXGUI_ORIENTATION_VERTICAL - static const short int width = 480; - static const short int height = 800; + static const short int width = 480; + static const short int height = 800; #elif defined MXGUI_ORIENTATION_HORIZONTAL - static const short int width = 800; - static const short int height = 480; + static const short int width = 800; + static const short int height = 480; #elif defined MXGUI_ORIENTATION_VERTICAL_MIRRORED || \ defined MXGUI_ORIENTATION_HORIZONTAL_MIRRORED #error unsupported orientation @@ -716,19 +717,19 @@ private: #error No orientation defined #endif - /** - * Pointer to the memory mapped display. - */ - Color* const framebuffer1; - Color* buffer; ///< For scanLineBuffer - pixel_iterator last; ///< Last iterator for end of iteration check - static const unsigned int bpp = sizeof(Color); ///< Bytes per pixel - static const int numPixels = - width * height; ///< Number of pixels of the display -}; + /** + * Pointer to the memory mapped display. + */ + Color *const framebuffer1; + Color *buffer; ///< For scanLineBuffer + pixel_iterator last; ///< Last iterator for end of iteration check + static const unsigned int bpp = sizeof(Color); ///< Bytes per pixel + static const int numPixels = + width * height; ///< Number of pixels of the display + }; -} // namespace mxgui +} // namespace mxgui -#endif //_BOARD_STM32F469NI_STM32F469I_DISCO +#endif //_BOARD_STM32F469NI_STM32F469I_DISCO -#endif // DISPLAY_STM32F4DISCOVERY_H +#endif // DISPLAY_STM32F4DISCOVERY_H diff --git a/mxgui/drivers/event_stm32f4discovery.cpp b/mxgui/drivers/event_stm32f4discovery.cpp index 1341b2c1334374cf68d832cdc8d5647076b493bc..04561b6496fb868c2598e89a2d8982143e5ceb73 100644 --- a/mxgui/drivers/event_stm32f4discovery.cpp +++ b/mxgui/drivers/event_stm32f4discovery.cpp @@ -43,6 +43,7 @@ defined(_BOARD_STM32F429ZI_HRE_TEST_STAND) || \ defined(_BOARD_STM32F429ZI_SKYWARD_PYXIS_AUXILIARY) || \ defined(_BOARD_STM32F429ZI_SKYWARD_PARAFOIL) || \ + defined(_BOARD_STM32F429ZI_SKYWARD_RIG) || \ defined(_BOARD_STM32F205RC_SKYWARD_CIUTI) && defined(MXGUI_LEVEL_2) #include <algorithm> @@ -55,7 +56,7 @@ using namespace std; using namespace miosix; -static Thread *waiting = 0; +static Thread *waiting = 0; static volatile bool irq = false; static volatile int flag = 0; @@ -115,284 +116,284 @@ void __attribute__((used)) EXTI0HandlerImpl() namespace mxgui { -typedef Gpio<GPIOA_BASE, 0> buttonA; -typedef Gpio<GPIOA_BASE, 8> scl; // I2C3 SCL -typedef Gpio<GPIOC_BASE, 9> sda; // I2C3 SDA -typedef Gpio<GPIOA_BASE, 15> interrupt; + typedef Gpio<GPIOA_BASE, 0> buttonA; + typedef Gpio<GPIOA_BASE, 8> scl; // I2C3 SCL + typedef Gpio<GPIOC_BASE, 9> sda; // I2C3 SDA + typedef Gpio<GPIOA_BASE, 15> interrupt; -typedef SoftwareI2C<sda, scl> stmpe811; + typedef SoftwareI2C<sda, scl> stmpe811; -/** - * The registers of the stmpe811 touchscreen controller - */ -enum stmpe811regs -{ - SYS_CTRL1 = 0x03, - SYS_CTRL2 = 0x04, - INT_CTRL = 0x09, - INT_EN = 0x0a, - INT_STA = 0x0B, - TSC_CTRL = 0x40, - TSC_CFG = 0x41, - FIFO_TH = 0x4a, - FIFO_STA = 0x4b, - TSC_DATA = 0xd7, - FIFO_SIZE = 0x4C -}; - -/** - * Write into a register in the stmpe811 - * \param reg register number - * \param val value to be written in the register - */ -static void stmpe811writeReg(unsigned char reg, unsigned char val) -{ - stmpe811::sendStart(); - stmpe811::send(0x82); - stmpe811::send(reg); - stmpe811::send(val); - stmpe811::sendStop(); -} - -/** - * Read from a register of the stmpe811 - * \param reg register number - * \param n number of bytes to read from register - * \param pointer to a memory area of at least n bytes where the read data will - * be stored - */ -static void stmpe811readReg(unsigned char reg, int n, unsigned char *result) -{ - if (n <= 0) - return; - stmpe811::sendStart(); - stmpe811::send(0x82); - stmpe811::send(reg); - stmpe811::sendStop(); - stmpe811::sendStart(); - stmpe811::send(0x82 | 1); - for (int i = 0; i < n - 1; i++) - result[i] = stmpe811::recvWithAck(); - result[n - 1] = stmpe811::recvWithNack(); - stmpe811::sendStop(); -} - -/** - * Clear the stmpe811 fifo - */ -static void touchFifoClear() -{ - stmpe811writeReg(FIFO_STA, 0x01); // RESET FIFO - stmpe811writeReg(FIFO_STA, 0x00); // RESET FIFO -} + /** + * The registers of the stmpe811 touchscreen controller + */ + enum stmpe811regs + { + SYS_CTRL1 = 0x03, + SYS_CTRL2 = 0x04, + INT_CTRL = 0x09, + INT_EN = 0x0a, + INT_STA = 0x0B, + TSC_CTRL = 0x40, + TSC_CFG = 0x41, + FIFO_TH = 0x4a, + FIFO_STA = 0x4b, + TSC_DATA = 0xd7, + FIFO_SIZE = 0x4C + }; + + /** + * Write into a register in the stmpe811 + * \param reg register number + * \param val value to be written in the register + */ + static void stmpe811writeReg(unsigned char reg, unsigned char val) + { + stmpe811::sendStart(); + stmpe811::send(0x82); + stmpe811::send(reg); + stmpe811::send(val); + stmpe811::sendStop(); + } -/** - * \return the touch point or (-1,-1) if no touch is in progress - */ -static Point getTouchData() -{ - unsigned char ctrl; - stmpe811readReg(TSC_CTRL, 1, &ctrl); - if ((ctrl & 0x80) == 0) + /** + * Read from a register of the stmpe811 + * \param reg register number + * \param n number of bytes to read from register + * \param pointer to a memory area of at least n bytes where the read data will + * be stored + */ + static void stmpe811readReg(unsigned char reg, int n, unsigned char *result) { - flag = 0; - return Point(-1, -1); + if (n <= 0) + return; + stmpe811::sendStart(); + stmpe811::send(0x82); + stmpe811::send(reg); + stmpe811::sendStop(); + stmpe811::sendStart(); + stmpe811::send(0x82 | 1); + for (int i = 0; i < n - 1; i++) + result[i] = stmpe811::recvWithAck(); + result[n - 1] = stmpe811::recvWithNack(); + stmpe811::sendStop(); } - if (flag == 0) + + /** + * Clear the stmpe811 fifo + */ + static void touchFifoClear() { - flag = 1; - return Point(-1, -1); + stmpe811writeReg(FIFO_STA, 0x01); // RESET FIFO + stmpe811writeReg(FIFO_STA, 0x00); // RESET FIFO } - else + + /** + * \return the touch point or (-1,-1) if no touch is in progress + */ + static Point getTouchData() { - unsigned char tsData[3]; - stmpe811readReg(TSC_DATA, 3, tsData); - stmpe811writeReg(FIFO_STA, 0x01); // RESET FIFO - stmpe811writeReg(FIFO_STA, 0x00); // RESET FIFO - int x = static_cast<int>(tsData[0]) << 4 | tsData[1] >> 4; - int y = ((static_cast<int>(tsData[1]) & 0xf) << 8) | tsData[2]; - x = 4095 - x; // X is swapped - // Calibration values. May vary from unit to unit - const int xMin = 300; - const int xMax = 3770; - const int yMin = 300; - const int yMax = 3880; - - x = ((x - xMin) * 240) / (xMax - xMin); - y = ((y - yMin) * 320) / (yMax - yMin); - x = min(239, max(0, x)); - y = min(319, max(0, y)); - return Point(x, y); + unsigned char ctrl; + stmpe811readReg(TSC_CTRL, 1, &ctrl); + if ((ctrl & 0x80) == 0) + { + flag = 0; + return Point(-1, -1); + } + if (flag == 0) + { + flag = 1; + return Point(-1, -1); + } + else + { + unsigned char tsData[3]; + stmpe811readReg(TSC_DATA, 3, tsData); + stmpe811writeReg(FIFO_STA, 0x01); // RESET FIFO + stmpe811writeReg(FIFO_STA, 0x00); // RESET FIFO + int x = static_cast<int>(tsData[0]) << 4 | tsData[1] >> 4; + int y = ((static_cast<int>(tsData[1]) & 0xf) << 8) | tsData[2]; + x = 4095 - x; // X is swapped + // Calibration values. May vary from unit to unit + const int xMin = 300; + const int xMax = 3770; + const int yMin = 300; + const int yMax = 3880; + + x = ((x - xMin) * 240) / (xMax - xMin); + y = ((y - yMin) * 320) / (yMax - yMin); + x = min(239, max(0, x)); + y = min(319, max(0, y)); + return Point(x, y); + } } -} -static Queue<Event, 10> eventQueue; -static std::function<void()> eventCallback; + static Queue<Event, 10> eventQueue; + static std::function<void()> eventCallback; -static void callback(Event e) -{ + static void callback(Event e) { - FastInterruptDisableLock dLock; - if (eventQueue.IRQput(e) == false) - return; + { + FastInterruptDisableLock dLock; + if (eventQueue.IRQput(e) == false) + return; + } + if (eventCallback) + eventCallback(); } - if (eventCallback) - eventCallback(); -} -static void waitForTouchOrButton() -{ + static void waitForTouchOrButton() { - FastInterruptDisableLock dLock2; - if (irq == false) { - waiting = Thread::IRQgetCurrentThread(); - while (waiting) + FastInterruptDisableLock dLock2; + if (irq == false) { - Thread::IRQwait(); - FastInterruptEnableLock eLock(dLock2); - Thread::yield(); + waiting = Thread::IRQgetCurrentThread(); + while (waiting) + { + Thread::IRQwait(); + FastInterruptEnableLock eLock(dLock2); + Thread::yield(); + } } + irq = false; } - irq = false; + stmpe811writeReg(INT_STA, 0x03); } - stmpe811writeReg(INT_STA, 0x03); -} -static void eventThread(void *) -{ - bool aPrev = false; - bool tPrev = false; - Point pOld; - for (;;) + static void eventThread(void *) { - waitForTouchOrButton(); - - // Check buttons - if (buttonA::value() == 1) - { - if (aPrev == false) - callback(Event(EventType::ButtonA, EventDirection::DOWN)); - aPrev = true; - } - else - { - if (aPrev == true) - callback(Event(EventType::ButtonA, EventDirection::UP)); - aPrev = false; - } - // Check touchscreen - Point p = getTouchData(); - if (p.x() >= 0) // Is someone touching the screen? + bool aPrev = false; + bool tPrev = false; + Point pOld; + for (;;) { - // Ok, someone is touching the screen - // Did the touch point differ that much from the previous? - if (abs(pOld.x() - p.x()) > 3 || abs(pOld.y() - p.y()) > 3 || - !tPrev) + waitForTouchOrButton(); + + // Check buttons + if (buttonA::value() == 1) { - pOld = p; - if (tPrev == false) - callback(Event(EventType::TouchDown, pOld, - EventDirection::DOWN)); - else - callback(Event(EventType::TouchMove, pOld, - EventDirection::DOWN)); + if (aPrev == false) + callback(Event(EventType::ButtonA, EventDirection::DOWN)); + aPrev = true; } - tPrev = true; - } - else - { - // No, no one is touching the screen - if (tPrev == true) + else { - touchFifoClear(); - callback(Event(EventType::TouchUp, pOld, EventDirection::UP)); + if (aPrev == true) + callback(Event(EventType::ButtonA, EventDirection::UP)); + aPrev = false; + } + // Check touchscreen + Point p = getTouchData(); + if (p.x() >= 0) // Is someone touching the screen? + { + // Ok, someone is touching the screen + // Did the touch point differ that much from the previous? + if (abs(pOld.x() - p.x()) > 3 || abs(pOld.y() - p.y()) > 3 || + !tPrev) + { + pOld = p; + if (tPrev == false) + callback(Event(EventType::TouchDown, pOld, + EventDirection::DOWN)); + else + callback(Event(EventType::TouchMove, pOld, + EventDirection::DOWN)); + } + tPrev = true; + } + else + { + // No, no one is touching the screen + if (tPrev == true) + { + touchFifoClear(); + callback(Event(EventType::TouchUp, pOld, EventDirection::UP)); + } + tPrev = false; } - tPrev = false; } } -} -// -// class InputHandlerImpl -// + // + // class InputHandlerImpl + // -InputHandlerImpl::InputHandlerImpl() -{ + InputHandlerImpl::InputHandlerImpl() { - FastInterruptDisableLock dLock; - buttonA::mode(Mode::INPUT_PULL_DOWN); - interrupt::mode(Mode::INPUT); - stmpe811::init(); - } + { + FastInterruptDisableLock dLock; + buttonA::mode(Mode::INPUT_PULL_DOWN); + interrupt::mode(Mode::INPUT); + stmpe811::init(); + } - // To let the I2C voltages settle - Thread::sleep(5); - - stmpe811writeReg(SYS_CTRL1, 0x02); // SOFT_RESET=1 - Thread::sleep(10); - stmpe811writeReg(SYS_CTRL1, 0x00); // SOFT_RESET=0 - Thread::sleep(2); - stmpe811writeReg(SYS_CTRL2, 0x08); // !GPIO_OFF !TSC_OFF !ADC_OFF - - // Total time to read the touchscreen is - // TDD*2+SETTLING*3+AVE*17.2us*3= ~ 17.5ms - stmpe811writeReg(TSC_CFG, 0xe4); // TSC_CFG= AVE=8, TDD=1ms, SETTLING=5ms - stmpe811writeReg(FIFO_TH, 0x01); // FIFO_TH= 1 - stmpe811writeReg(FIFO_STA, 0x01); // RESET FIFO - stmpe811writeReg(FIFO_STA, 0x00); // RESET FIFO - - // This may allow the chip to go out of hibernate once touch detected - stmpe811writeReg(INT_CTRL, 0x01); - stmpe811writeReg(INT_EN, 0x03); - - stmpe811writeReg( - TSC_CTRL, 0x73); // TSC_CTRL=No window track, XY, Enabled - // 0xA3 Rumore escluso. impostare A da 1(min) a 7(max) - // per modificare l'assorbimento del rumore sul touch - // impostiamo registri - stmpe811writeReg(FIFO_TH, 0x01); - - // impostiamo l'interrupt del touchscreen - EXTI->IMR |= EXTI_IMR_MR15; - EXTI->FTSR |= EXTI_FTSR_TR15; - NVIC_EnableIRQ(EXTI15_10_IRQn); - NVIC_SetPriority(EXTI15_10_IRQn, 15); // Low priority - - // impostiamo l'interrupt del bottone - EXTI->IMR |= EXTI_IMR_MR0; - EXTI->RTSR |= EXTI_RTSR_TR0; - EXTI->FTSR |= EXTI_FTSR_TR0; - NVIC_EnableIRQ(EXTI0_IRQn); - NVIC_SetPriority(EXTI0_IRQn, 15); // Low priority - - // Note that this class is instantiated only once. Otherwise - // we'd have to think a way to avoid creating multiple threads - Thread::create(eventThread, STACK_MIN); -} + // To let the I2C voltages settle + Thread::sleep(5); + + stmpe811writeReg(SYS_CTRL1, 0x02); // SOFT_RESET=1 + Thread::sleep(10); + stmpe811writeReg(SYS_CTRL1, 0x00); // SOFT_RESET=0 + Thread::sleep(2); + stmpe811writeReg(SYS_CTRL2, 0x08); // !GPIO_OFF !TSC_OFF !ADC_OFF + + // Total time to read the touchscreen is + // TDD*2+SETTLING*3+AVE*17.2us*3= ~ 17.5ms + stmpe811writeReg(TSC_CFG, 0xe4); // TSC_CFG= AVE=8, TDD=1ms, SETTLING=5ms + stmpe811writeReg(FIFO_TH, 0x01); // FIFO_TH= 1 + stmpe811writeReg(FIFO_STA, 0x01); // RESET FIFO + stmpe811writeReg(FIFO_STA, 0x00); // RESET FIFO + + // This may allow the chip to go out of hibernate once touch detected + stmpe811writeReg(INT_CTRL, 0x01); + stmpe811writeReg(INT_EN, 0x03); + + stmpe811writeReg( + TSC_CTRL, 0x73); // TSC_CTRL=No window track, XY, Enabled + // 0xA3 Rumore escluso. impostare A da 1(min) a 7(max) + // per modificare l'assorbimento del rumore sul touch + // impostiamo registri + stmpe811writeReg(FIFO_TH, 0x01); + + // impostiamo l'interrupt del touchscreen + EXTI->IMR |= EXTI_IMR_MR15; + EXTI->FTSR |= EXTI_FTSR_TR15; + NVIC_EnableIRQ(EXTI15_10_IRQn); + NVIC_SetPriority(EXTI15_10_IRQn, 15); // Low priority + + // impostiamo l'interrupt del bottone + EXTI->IMR |= EXTI_IMR_MR0; + EXTI->RTSR |= EXTI_RTSR_TR0; + EXTI->FTSR |= EXTI_FTSR_TR0; + NVIC_EnableIRQ(EXTI0_IRQn); + NVIC_SetPriority(EXTI0_IRQn, 15); // Low priority + + // Note that this class is instantiated only once. Otherwise + // we'd have to think a way to avoid creating multiple threads + Thread::create(eventThread, STACK_MIN); + } -Event InputHandlerImpl::getEvent() -{ - Event result; - eventQueue.get(result); - return result; -} + Event InputHandlerImpl::getEvent() + { + Event result; + eventQueue.get(result); + return result; + } -Event InputHandlerImpl::popEvent() -{ - FastInterruptDisableLock dLock; - Event result; - if (eventQueue.isEmpty() == false) - eventQueue.IRQget(result); - return result; -} + Event InputHandlerImpl::popEvent() + { + FastInterruptDisableLock dLock; + Event result; + if (eventQueue.isEmpty() == false) + eventQueue.IRQget(result); + return result; + } -function<void()> InputHandlerImpl::registerEventCallback(function<void()> cb) -{ - swap(eventCallback, cb); - return cb; -} + function<void()> InputHandlerImpl::registerEventCallback(function<void()> cb) + { + swap(eventCallback, cb); + return cb; + } -} // namespace mxgui +} // namespace mxgui -#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY +#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY diff --git a/mxgui/drivers/event_stm32f4discovery.h b/mxgui/drivers/event_stm32f4discovery.h index 60ce9578f8cf37f6816073d6fea317d8247cf052..8334fe87c0454feb78becc86489ccae8987a9965 100644 --- a/mxgui/drivers/event_stm32f4discovery.h +++ b/mxgui/drivers/event_stm32f4discovery.h @@ -28,7 +28,7 @@ #ifndef MXGUI_LIBRARY #error "This is header is private, it can be used only within mxgui." #error "If your code depends on a private header, it IS broken." -#endif // MXGUI_LIBRARY +#endif // MXGUI_LIBRARY #include <functional> @@ -52,46 +52,47 @@ defined(_BOARD_STM32F429ZI_HRE_TEST_STAND) || \ defined(_BOARD_STM32F429ZI_SKYWARD_PYXIS_AUXILIARY) || \ defined(_BOARD_STM32F429ZI_SKYWARD_PARAFOIL) || \ - defined(_BOARD_STM32F205RC_SKYWARD_CIUTI) + defined(_BOARD_STM32F205RC_SKYWARD_CIUTI) || \ + defined(_BOARD_STM32F429ZI_SKYWARD_RIG) namespace mxgui { -/** - * Implementation class to handle events in the Mp3v2 backend - */ -class InputHandlerImpl -{ -public: - InputHandlerImpl(); - /** - * \return an event, blocking + * Implementation class to handle events in the Mp3v2 backend */ - Event getEvent(); + class InputHandlerImpl + { + public: + InputHandlerImpl(); - /** - * \return an event, nonblocking. A default constructed event is returned - * if there are no events. - */ - Event popEvent(); + /** + * \return an event, blocking + */ + Event getEvent(); - /** - * Register a callback that will be called every time an event is geenrated - * - * Note: the thread calling the callback has a very small stack. - * - * Note: concurrent access to this memebr function causes undefined - * behaviour - * - * \param cb new callback to register - * \return the previous callback - */ - std::function<void()> registerEventCallback(std::function<void()> cb); -}; + /** + * \return an event, nonblocking. A default constructed event is returned + * if there are no events. + */ + Event popEvent(); + + /** + * Register a callback that will be called every time an event is geenrated + * + * Note: the thread calling the callback has a very small stack. + * + * Note: concurrent access to this memebr function causes undefined + * behaviour + * + * \param cb new callback to register + * \return the previous callback + */ + std::function<void()> registerEventCallback(std::function<void()> cb); + }; -} // namespace mxgui +} // namespace mxgui -#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY +#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY -#endif // EVENT_STM32F4DISCOVERY_H +#endif // EVENT_STM32F4DISCOVERY_H diff --git a/mxgui/drivers/event_types_stm32f4discovery.h b/mxgui/drivers/event_types_stm32f4discovery.h index 6eb398beec960621b9f65c1df8ebc799485c1b11..587502a1bcdc708454307adce67dce1c04695477 100644 --- a/mxgui/drivers/event_types_stm32f4discovery.h +++ b/mxgui/drivers/event_types_stm32f4discovery.h @@ -43,7 +43,8 @@ defined(_BOARD_STM32F429ZI_HRE_TEST_STAND) || \ defined(_BOARD_STM32F429ZI_SKYWARD_PYXIS_AUXILIARY) || \ defined(_BOARD_STM32F429ZI_SKYWARD_PARAFOIL) || \ - defined(_BOARD_STM32F205RC_SKYWARD_CIUTI) + defined(_BOARD_STM32F205RC_SKYWARD_CIUTI) || \ + defined(_BOARD_STM32F429ZI_SKYWARD_RIG) class EventType { @@ -51,23 +52,23 @@ public: enum E { // These are a must on all backends -- begin - Default = 0, // This actually means 'no event' - WindowPartialRedraw, // At least one drawable has requested redraw - WindowForeground, // Window manager moved this window to foreground - WindowBackground, // Window manager moved this window to background - WindowQuit, // Window manager requested the window to close - // These are a must on all backends -- end + Default = 0, // This actually means 'no event' + WindowPartialRedraw, // At least one drawable has requested redraw + WindowForeground, // Window manager moved this window to foreground + WindowBackground, // Window manager moved this window to background + WindowQuit, // Window manager requested the window to close + // These are a must on all backends -- end TouchDown = 1, - TouchUp = 2, + TouchUp = 2, TouchMove = 3, - ButtonA = 4 // The blue button + ButtonA = 4 // The blue button }; private: EventType(); }; -#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY +#endif //_BOARD_STM32F429ZI_STM32F4DISCOVERY -#endif // EVENT_TYPES_STM32F4DISCOVERY_H +#endif // EVENT_TYPES_STM32F4DISCOVERY_H