From b4bd41cd562f89bcd320ac0985e9b33c766babe1 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 19 Jan 2020 19:47:49 +0100 Subject: [PATCH 1/6] Implement the SPI driver using DMA. --- CMakeLists.txt | 2 +- src/Components/Gfx/Gfx.cpp | 28 +++++++-- src/Components/Gfx/Gfx.h | 8 ++- src/DisplayApp/DisplayApp.cpp | 24 +++++--- src/DisplayApp/DisplayApp.h | 4 +- src/drivers/SpiMaster.cpp | 111 +++++++++++++++++++++++++++------- src/drivers/SpiMaster.h | 7 ++- src/drivers/St7789.cpp | 18 +----- src/drivers/St7789.h | 1 - 9 files changed, 143 insertions(+), 60 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 063decbe..21c63797 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(pinetime VERSION 0.2.0 LANGUAGES C CXX ASM) +project(pinetime VERSION 0.2.99 LANGUAGES C CXX ASM) set(NRF_TARGET "nrf52") diff --git a/src/Components/Gfx/Gfx.cpp b/src/Components/Gfx/Gfx.cpp index 9e680687..6c19518a 100644 --- a/src/Components/Gfx/Gfx.cpp +++ b/src/Components/Gfx/Gfx.cpp @@ -11,11 +11,21 @@ void Gfx::Init() { } void Gfx::ClearScreen() { - lcd.FillRectangle(0, 0, width, height, 0x0000); + SetBackgroundColor(0x0000); + lcd.BeginDrawBuffer(0, 0, width, height); + for(int i = 0; i < height; i++) { + lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2); + } + lcd.EndDrawBuffer(); } void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color) { - lcd.FillRectangle(x, y, width, height, color); + SetBackgroundColor(color); + lcd.BeginDrawBuffer(0, 0, width, height); + for(int i = 0; i < height; i++) { + lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2); + } + lcd.EndDrawBuffer(); } void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) { @@ -70,15 +80,15 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint for (uint16_t i = 0; i < font->height; i++) { for (uint16_t j = 0; j < bytes_in_line; j++) { for (uint8_t k = 0; k < 8; k++) { - if ((1 << (7 - k)) & - font->data[font->charInfo[char_idx].offset + i * bytes_in_line + j]) { - lcd.NextDrawBuffer(reinterpret_cast(&color), 2); + if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + i * bytes_in_line + j]) { + buffer[(j*8)+k] = color; } else { - lcd.NextDrawBuffer(reinterpret_cast(&bg), 2); + buffer[(j*8)+k] = bg; } } } + lcd.NextDrawBuffer(reinterpret_cast(&buffer), bytes_in_line*8*2); } lcd.EndDrawBuffer(); *x += font->charInfo[char_idx].widthBits + font->spacePixels; @@ -96,4 +106,10 @@ void Gfx::Wakeup() { lcd.Wakeup(); } +void Gfx::SetBackgroundColor(uint16_t color) { + for(int i = 0; i < width; i++) { + buffer[i] = color; + } +} + diff --git a/src/Components/Gfx/Gfx.h b/src/Components/Gfx/Gfx.h index 9bd07fee..d8728701 100644 --- a/src/Components/Gfx/Gfx.h +++ b/src/Components/Gfx/Gfx.h @@ -21,10 +21,14 @@ namespace Pinetime { void Wakeup(); private: + static constexpr uint8_t width = 240; + static constexpr uint8_t height = 240; + + uint16_t buffer[width]; // 1 line buffer Drivers::St7789& lcd; - const uint8_t width = 240; - const uint8_t height = 240; + void pixel_draw(uint8_t x, uint8_t y, uint16_t color); + void SetBackgroundColor(uint16_t color); }; } } diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index 3b7007af..29c75fa8 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -31,8 +31,8 @@ DisplayApp::DisplayApp(Controllers::Battery &batteryController, batteryController{batteryController}, bleController{bleController}, dateTimeController{dateTimeController}, - clockScreen{*(gfx.get())}/*, - messageScreen{*(gfx.get())}*/ { + clockScreen{*(gfx.get())}, + messageScreen{*(gfx.get())} { msgQueue = xQueueCreate(queueSize, itemSize); currentScreen = &clockScreen; } @@ -121,16 +121,20 @@ void DisplayApp::Refresh() { void DisplayApp::RunningState() { clockScreen.SetCurrentDateTime(dateTimeController.CurrentDateTime()); +// if(currentScreen != nullptr) { +// currentScreen->Refresh(false); +// } + if(currentScreen != nullptr) { - currentScreen->Refresh(false); + currentScreen->Refresh(true); } -// if(screenState) { -// currentScreen = &clockScreen; -// } else { -// currentScreen = &messageScreen; -// } -// screenState = !screenState; + if(screenState) { + currentScreen = &clockScreen; + } else { + currentScreen = &messageScreen; + } + screenState = !screenState; } @@ -153,7 +157,7 @@ void DisplayApp::OnTouchEvent() { auto info = touchPanel.GetTouchInfo(); if(info.isTouch) { - lcd->FillRectangle(info.x-10, info.y-10, 20,20, pointColor); + gfx->FillRectangle(info.x-10, info.y-10, 20,20, pointColor); pointColor+=10; } } diff --git a/src/DisplayApp/DisplayApp.h b/src/DisplayApp/DisplayApp.h index 5fb8f6f8..eabfe099 100644 --- a/src/DisplayApp/DisplayApp.h +++ b/src/DisplayApp/DisplayApp.h @@ -57,8 +57,8 @@ namespace Pinetime { Screens::Clock clockScreen; Screens::Screen* currentScreen = nullptr; -// Screens::Message messageScreen; -// bool screenState = false; + Screens::Message messageScreen; + bool screenState = false; static constexpr uint8_t pinSpiSck = 2; static constexpr uint8_t pinSpiMosi = 3; static constexpr uint8_t pinSpiMiso = 4; diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 42d3d77b..e8130c76 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -1,6 +1,7 @@ #include +#include #include "SpiMaster.h" - +#include using namespace Pinetime::Drivers; SpiMaster::SpiMaster(const SpiMaster::SpiModule spi, const SpiMaster::Parameters ¶ms) : @@ -9,22 +10,24 @@ SpiMaster::SpiMaster(const SpiMaster::SpiModule spi, const SpiMaster::Parameters bool SpiMaster::Init() { /* Configure GPIO pins used for pselsck, pselmosi, pselmiso and pselss for SPI0 */ + nrf_gpio_pin_set(params.pinSCK); nrf_gpio_cfg_output(params.pinSCK); + nrf_gpio_pin_clear(params.pinMOSI); nrf_gpio_cfg_output(params.pinMOSI); nrf_gpio_cfg_input(params.pinMISO, NRF_GPIO_PIN_NOPULL); nrf_gpio_cfg_output(params.pinCSN); pinCsn = params.pinCSN; switch(spi) { - case SpiModule::SPI0: spiBaseAddress = NRF_SPI0; break; - case SpiModule::SPI1: spiBaseAddress = NRF_SPI1; break; + case SpiModule::SPI0: spiBaseAddress = NRF_SPIM0; break; + case SpiModule::SPI1: spiBaseAddress = NRF_SPIM1; break; default: return false; } /* Configure pins, frequency and mode */ - spiBaseAddress->PSELSCK = params.pinSCK; - spiBaseAddress->PSELMOSI = params.pinMOSI; - spiBaseAddress->PSELMISO = params.pinMISO; + NRF_SPIM0->PSELSCK = params.pinSCK; + NRF_SPIM0->PSELMOSI = params.pinMOSI; + NRF_SPIM0->PSELMISO = params.pinMISO; nrf_gpio_pin_set(pinCsn); /* disable Set slave select (inactive high) */ uint32_t frequency; @@ -32,7 +35,7 @@ bool SpiMaster::Init() { case Frequencies::Freq8Mhz: frequency = 0x80000000; break; default: return false; } - spiBaseAddress->FREQUENCY = frequency; + NRF_SPIM0->FREQUENCY = frequency; uint32_t regConfig = 0; switch(params.bitOrder) { @@ -48,14 +51,21 @@ bool SpiMaster::Init() { default: return false; } - spiBaseAddress->CONFIG = regConfig; - spiBaseAddress->EVENTS_READY = 0; - spiBaseAddress->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos); + setup_workaround_for_ftpan_58(NRF_SPIM0, 0, 0); + + NRF_SPIM0->CONFIG = regConfig; + NRF_SPIM0->EVENTS_ENDRX = 0; + NRF_SPIM0->EVENTS_ENDTX = 0; + NRF_SPIM0->EVENTS_END = 0; + NRF_SPI0->EVENTS_READY = 0; + NRF_SPI0->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos); + NRF_SPIM0->ENABLE = (SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos); return true; } -bool SpiMaster::Write(const uint8_t *data, size_t size) { +bool SpiMaster::WriteFast(const uint8_t *data, size_t size) { + auto spi = reinterpret_cast(spiBaseAddress); volatile uint32_t dummyread; if(data == nullptr) return false; @@ -63,27 +73,27 @@ bool SpiMaster::Write(const uint8_t *data, size_t size) { /* enable slave (slave select active low) */ nrf_gpio_pin_clear(pinCsn); - spiBaseAddress->EVENTS_READY = 0; + NRF_SPI0->EVENTS_READY = 0; - spiBaseAddress->TXD = (uint32_t)*data++; + NRF_SPI0->TXD = (uint32_t)*data++; while(--size) { - spiBaseAddress->TXD = (uint32_t)*data++; + NRF_SPI0->TXD = (uint32_t)*data++; /* Wait for the transaction complete or timeout (about 10ms - 20 ms) */ - while (spiBaseAddress->EVENTS_READY == 0); + while (NRF_SPI0->EVENTS_READY == 0); /* clear the event to be ready to receive next messages */ - spiBaseAddress->EVENTS_READY = 0; + NRF_SPI0->EVENTS_READY = 0; - dummyread = spiBaseAddress->RXD; + dummyread = NRF_SPI0->RXD; } /* Wait for the transaction complete or timeout (about 10ms - 20 ms) */ - while (spiBaseAddress->EVENTS_READY == 0); + while (NRF_SPI0->EVENTS_READY == 0); - dummyread = spiBaseAddress->RXD; + dummyread = NRF_SPI0->RXD; /* disable slave (slave select active low) */ nrf_gpio_pin_set(pinCsn); @@ -91,9 +101,68 @@ bool SpiMaster::Write(const uint8_t *data, size_t size) { return true; } +void SpiMaster::setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel) { + // Create an event when SCK toggles. + NRF_GPIOTE->CONFIG[gpiote_channel] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | + (spim->PSEL.SCK << GPIOTE_CONFIG_PSEL_Pos) | + (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos); + + // Stop the spim instance when SCK toggles. + NRF_PPI->CH[ppi_channel].EEP = (uint32_t) &NRF_GPIOTE->EVENTS_IN[gpiote_channel]; + NRF_PPI->CH[ppi_channel].TEP = (uint32_t) &spim->TASKS_STOP; + NRF_PPI->CHENSET = 1U << ppi_channel; +} + +bool SpiMaster::Write(const uint8_t *data, size_t size) { + if(data == nullptr) return false; + + if(size == 1) { + setup_workaround_for_ftpan_58(NRF_SPIM0, 0,0); + } else { + NRF_GPIOTE->CONFIG[0] = 0; + NRF_PPI->CH[0].EEP = 0; + NRF_PPI->CH[0].TEP = 0; + NRF_PPI->CHENSET = 0; + } + + nrf_gpio_pin_clear(pinCsn); + auto spim = reinterpret_cast(spiBaseAddress); + + while(size > 0) { + auto currentSize = std::min((size_t)255, size); + size -= currentSize; + NRF_SPIM0->TXD.PTR = (uint32_t) data; + NRF_SPIM0->TXD.MAXCNT = currentSize; + NRF_SPIM0->TXD.LIST = 0; + + NRF_SPIM0->RXD.PTR = (uint32_t) 0; + NRF_SPIM0->RXD.MAXCNT = 0; + NRF_SPIM0->RXD.LIST = 0; + + NRF_SPIM0->EVENTS_END = 0; + + NRF_SPIM0->TASKS_START = 1; + + + while (NRF_SPIM0->EVENTS_END == 0); + } + + nrf_gpio_pin_set(pinCsn); + + return true; +} + +bool SpiMaster::GetStatusEnd() { + return (bool)*(volatile uint32_t *)((uint8_t *)spiBaseAddress + (uint32_t)NRF_SPIM_EVENT_END); +} + +bool SpiMaster::GetStatusStarted() { + return (bool)*(volatile uint32_t *)((uint8_t *)spiBaseAddress + (uint32_t)NRF_SPIM_EVENT_STARTED); +} + void SpiMaster::Sleep() { - while(NRF_SPI0->ENABLE != 0) { - NRF_SPI0->ENABLE = (SPIM_ENABLE_ENABLE_Disabled << SPIM_ENABLE_ENABLE_Pos); + while(NRF_SPIM0->ENABLE != 0) { + NRF_SPIM0->ENABLE = (SPIM_ENABLE_ENABLE_Disabled << SPIM_ENABLE_ENABLE_Pos); } nrf_gpio_cfg_default(params.pinSCK); nrf_gpio_cfg_default(params.pinMOSI); diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 073501a8..5376ac8e 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -24,12 +24,17 @@ namespace Pinetime { SpiMaster(const SpiModule spi, const Parameters& params); bool Init(); bool Write(const uint8_t* data, size_t size); + bool WriteFast(const uint8_t* data, size_t size); + void setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); void Sleep(); void Wakeup(); + bool GetStatusEnd(); + bool GetStatusStarted(); + private: - NRF_SPI_Type * spiBaseAddress; + NRF_SPIM_Type * spiBaseAddress; uint8_t pinCsn; SpiMaster::SpiModule spi; diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index ac813064..f47c2f58 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -38,7 +38,7 @@ void St7789::WriteData(uint8_t data) { void St7789::WriteSpi(const uint8_t* data, size_t size) { - spi.Write(data, size); + spi.Write(data, size); } void St7789::SoftwareReset() { @@ -95,20 +95,6 @@ void St7789::DisplayOn() { WriteCommand(static_cast(Commands::DisplayOn)); } -void St7789::FillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) { - BeginDrawBuffer(x, y, width, height); - - uint32_t c = color + (color << 16); - uint8_t w = width/2; - - for(y=height+ST7789_ROW_OFFSET; y>ST7789_ROW_OFFSET; y--) { - for(x=w; x>0; x--) { - NextDrawBuffer(reinterpret_cast(&c), 4); - } - } - EndDrawBuffer(); -} - void St7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { WriteCommand(static_cast(Commands::ColumnAddressSet)); WriteData(x0 >> 8); @@ -160,7 +146,7 @@ void St7789::EndDrawBuffer() { } void St7789::NextDrawBuffer(const uint8_t *data, size_t size) { - spi.Write(data, size); + WriteSpi(data, size); } void St7789::HardwareReset() { diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index a32a96f9..8e4690b0 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -10,7 +10,6 @@ namespace Pinetime { void Init(); void Uninit(); void DrawPixel(uint16_t x, uint16_t y, uint32_t color); - void FillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color); void BeginDrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height); void NextDrawBuffer(const uint8_t* data, size_t size); From aa3e5c0c6f6f7bb9df02ae5d333dc6c4a6d2e744 Mon Sep 17 00:00:00 2001 From: JF Date: Wed, 22 Jan 2020 19:45:53 +0100 Subject: [PATCH 2/6] [WIP] Use IRQ in SPI driver to improve performances --- src/DisplayApp/Screens/Clock.cpp | 8 +-- src/DisplayApp/Screens/Message.cpp | 2 +- src/drivers/SpiMaster.cpp | 108 ++++++++++++++++------------- src/drivers/SpiMaster.h | 12 +++- src/main.cpp | 14 ++++ 5 files changed, 90 insertions(+), 54 deletions(-) diff --git a/src/DisplayApp/Screens/Clock.cpp b/src/DisplayApp/Screens/Clock.cpp index 153f4f2e..155cb581 100644 --- a/src/DisplayApp/Screens/Clock.cpp +++ b/src/DisplayApp/Screens/Clock.cpp @@ -9,10 +9,10 @@ using namespace Pinetime::Applications::Screens; void Clock::Refresh(bool fullRefresh) { if(fullRefresh) { gfx.FillRectangle(0,0,240,240,0x0000); - currentChar[0] = 0; - currentChar[1] = 0; - currentChar[2] = 0; - currentChar[3] = 0; + currentChar[0] = 1; + currentChar[1] = 2; + currentChar[2] = 3; + currentChar[3] = 4; auto dummy = currentDateTime.Get(); } diff --git a/src/DisplayApp/Screens/Message.cpp b/src/DisplayApp/Screens/Message.cpp index 2ade4349..121e34b9 100644 --- a/src/DisplayApp/Screens/Message.cpp +++ b/src/DisplayApp/Screens/Message.cpp @@ -9,6 +9,6 @@ using namespace Pinetime::Applications::Screens; void Message::Refresh(bool fullRefresh) { if(fullRefresh) { gfx.FillRectangle(0,0,240,240,0xffff); - gfx.DrawString(120, 10, 0x0000, "COUCOU", &smallFont, false); + gfx.DrawString(120, 10, 0x5555, "COUCOU", &smallFont, false); } } diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index e8130c76..f7e64db6 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -4,8 +4,10 @@ #include using namespace Pinetime::Drivers; +SpiMaster* spiInstance; SpiMaster::SpiMaster(const SpiMaster::SpiModule spi, const SpiMaster::Parameters ¶ms) : spi{spi}, params{params} { + spiInstance = this; } bool SpiMaster::Init() { @@ -57,49 +59,17 @@ bool SpiMaster::Init() { NRF_SPIM0->EVENTS_ENDRX = 0; NRF_SPIM0->EVENTS_ENDTX = 0; NRF_SPIM0->EVENTS_END = 0; - NRF_SPI0->EVENTS_READY = 0; - NRF_SPI0->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos); + + NRF_SPIM0->INTENSET = ((unsigned)1 << (unsigned)6); + NRF_SPIM0->INTENSET = ((unsigned)1 << (unsigned)1); + NRF_SPIM0->ENABLE = (SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos); + NRFX_IRQ_PRIORITY_SET(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn,6); + NRFX_IRQ_ENABLE(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn); return true; } -bool SpiMaster::WriteFast(const uint8_t *data, size_t size) { - auto spi = reinterpret_cast(spiBaseAddress); - volatile uint32_t dummyread; - - if(data == nullptr) return false; - - /* enable slave (slave select active low) */ - nrf_gpio_pin_clear(pinCsn); - - NRF_SPI0->EVENTS_READY = 0; - - NRF_SPI0->TXD = (uint32_t)*data++; - - while(--size) - { - NRF_SPI0->TXD = (uint32_t)*data++; - - /* Wait for the transaction complete or timeout (about 10ms - 20 ms) */ - while (NRF_SPI0->EVENTS_READY == 0); - - /* clear the event to be ready to receive next messages */ - NRF_SPI0->EVENTS_READY = 0; - - dummyread = NRF_SPI0->RXD; - } - - /* Wait for the transaction complete or timeout (about 10ms - 20 ms) */ - while (NRF_SPI0->EVENTS_READY == 0); - - dummyread = NRF_SPI0->RXD; - - /* disable slave (slave select active low) */ - nrf_gpio_pin_set(pinCsn); - - return true; -} void SpiMaster::setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel) { // Create an event when SCK toggles. @@ -113,41 +83,85 @@ void SpiMaster::setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_ NRF_PPI->CHENSET = 1U << ppi_channel; } + + +void SpiMaster::irq() { + if(busy) { + if(bufferSize > 0) { + auto currentSize = std::min((size_t)255, bufferSize); + + NRF_SPIM0->TXD.PTR = (uint32_t) bufferAddr; + NRF_SPIM0->TXD.MAXCNT = currentSize; + NRF_SPIM0->TXD.LIST = 0; + + bufferAddr += currentSize; + bufferSize -= currentSize; + + NRF_SPIM0->RXD.PTR = (uint32_t) 0; + NRF_SPIM0->RXD.MAXCNT = 0; + NRF_SPIM0->RXD.LIST = 0; + NRF_SPIM0->TASKS_START = 1; + + return; + }else { + nrf_gpio_pin_set(pinCsn); + busy = false; + } + } +} + bool SpiMaster::Write(const uint8_t *data, size_t size) { if(data == nullptr) return false; + while(busy) { + asm("nop"); + } + if(size == 1) { setup_workaround_for_ftpan_58(NRF_SPIM0, 0,0); + NRF_SPIM0->INTENCLR = (1<<6); + NRF_SPIM0->INTENCLR = (1<<1); + } else { NRF_GPIOTE->CONFIG[0] = 0; NRF_PPI->CH[0].EEP = 0; NRF_PPI->CH[0].TEP = 0; NRF_PPI->CHENSET = 0; + NRF_SPIM0->INTENSET = (1<<6); + NRF_SPIM0->INTENSET = (1<<1); } nrf_gpio_pin_clear(pinCsn); - auto spim = reinterpret_cast(spiBaseAddress); - while(size > 0) { - auto currentSize = std::min((size_t)255, size); - size -= currentSize; + bufferAddr = (uint32_t)data; + bufferSize = size; + busy = true; + +// while(size > 0) { + auto currentSize = std::min((size_t)255, bufferSize); NRF_SPIM0->TXD.PTR = (uint32_t) data; NRF_SPIM0->TXD.MAXCNT = currentSize; NRF_SPIM0->TXD.LIST = 0; + bufferSize -= currentSize; + bufferAddr += currentSize; + NRF_SPIM0->RXD.PTR = (uint32_t) 0; NRF_SPIM0->RXD.MAXCNT = 0; NRF_SPIM0->RXD.LIST = 0; - NRF_SPIM0->EVENTS_END = 0; + if(size != 1) { + NRF_SPIM0->EVENTS_END = 0; + } NRF_SPIM0->TASKS_START = 1; + if(size == 1) { + while (NRF_SPIM0->EVENTS_END == 0); + busy = false; + nrf_gpio_pin_set(pinCsn); + } - while (NRF_SPIM0->EVENTS_END == 0); - } - - nrf_gpio_pin_set(pinCsn); return true; } diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 5376ac8e..dff63e94 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -2,7 +2,7 @@ #include #include #include - +#include namespace Pinetime { namespace Drivers { class SpiMaster { @@ -24,7 +24,7 @@ namespace Pinetime { SpiMaster(const SpiModule spi, const Parameters& params); bool Init(); bool Write(const uint8_t* data, size_t size); - bool WriteFast(const uint8_t* data, size_t size); + bool WriteRepeat(const uint8_t *data, size_t size, int repeat); void setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); void Sleep(); @@ -33,12 +33,20 @@ namespace Pinetime { bool GetStatusEnd(); bool GetStatusStarted(); + void irq(); + private: NRF_SPIM_Type * spiBaseAddress; uint8_t pinCsn; SpiMaster::SpiModule spi; SpiMaster::Parameters params; + + std::atomic busy {false}; + + uint32_t bufferAddr = 0; + + size_t bufferSize = 0; }; } } diff --git a/src/main.cpp b/src/main.cpp index 062a36e4..14be5ca2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -158,6 +158,20 @@ void OnNewTime(current_time_char_t* currentTime) { dayOfWeek, hour, minute, second, nrf_rtc_counter_get(portNRF_RTC_REG)); } +extern Pinetime::Drivers::SpiMaster* spiInstance; +void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) { + if(((NRF_SPIM0->INTENSET & (1<<6)) != 0) && NRF_SPIM0->EVENTS_END == 1) { + NRF_SPIM0->EVENTS_END = 0; + spiInstance->irq(); + } + + + if(((NRF_SPIM0->INTENSET & (1<<1)) != 0) && NRF_SPIM0->EVENTS_STOPPED == 1) { + NRF_SPIM0->EVENTS_STOPPED = 0; + } + + return; +} int main(void) { displayApp.reset(new Pinetime::Applications::DisplayApp(batteryController, bleController, dateTimeController)); logger.Init(); From eb7a1b3ac9cbacb74afb7fcd1d40c51a18c90060 Mon Sep 17 00:00:00 2001 From: JF Date: Wed, 22 Jan 2020 21:08:53 +0100 Subject: [PATCH 3/6] [WIP] Max SPI speed reached (119ms for a full refresh. Theo max : 240*240*16 = 115.2ms) using IRQ and DMA. Code needs some cleaning before integration. --- src/Components/Gfx/Gfx.cpp | 4 +- src/DisplayApp/DisplayApp.cpp | 22 ++++++++ src/drivers/SpiMaster.cpp | 100 +++++++++++++++++++++++----------- src/drivers/SpiMaster.h | 13 +++-- src/drivers/St7789.cpp | 9 +-- src/drivers/St7789.h | 4 +- src/main.cpp | 7 ++- src/sdk_config.h | 6 +- 8 files changed, 114 insertions(+), 51 deletions(-) diff --git a/src/Components/Gfx/Gfx.cpp b/src/Components/Gfx/Gfx.cpp index 6c19518a..94106513 100644 --- a/src/Components/Gfx/Gfx.cpp +++ b/src/Components/Gfx/Gfx.cpp @@ -22,9 +22,7 @@ void Gfx::ClearScreen() { void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color) { SetBackgroundColor(color); lcd.BeginDrawBuffer(0, 0, width, height); - for(int i = 0; i < height; i++) { - lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2); - } + lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2, 240); lcd.EndDrawBuffer(); } diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index 29c75fa8..c1561cc2 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -65,7 +65,28 @@ void DisplayApp::InitHw() { touchPanel.Init(); } +uint32_t acc = 0; +uint32_t count = 0; +bool toggle = true; void DisplayApp::Refresh() { + + uint32_t before = nrf_rtc_counter_get(portNRF_RTC_REG); + if(toggle) { + gfx->FillRectangle(0,0,240,240,0x0000); + } else { + gfx->FillRectangle(0,0,240,240,0xffff); + } + uint32_t after = nrf_rtc_counter_get(portNRF_RTC_REG); + + acc += (after - before); + if((count % 10) == 0) { + NRF_LOG_INFO("DRAW : %d ms", (uint32_t)(acc/10)); + acc = 0; + } + count++; + toggle = !toggle; + +#if 0 TickType_t queueTimeout; switch (state) { case States::Idle: @@ -116,6 +137,7 @@ void DisplayApp::Refresh() { break; } } +#endif } void DisplayApp::RunningState() { diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index f7e64db6..7c6186a6 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -62,6 +62,7 @@ bool SpiMaster::Init() { NRF_SPIM0->INTENSET = ((unsigned)1 << (unsigned)6); NRF_SPIM0->INTENSET = ((unsigned)1 << (unsigned)1); + NRF_SPIM0->INTENSET = ((unsigned)1 << (unsigned)19); NRF_SPIM0->ENABLE = (SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos); @@ -83,34 +84,61 @@ void SpiMaster::setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_ NRF_PPI->CHENSET = 1U << ppi_channel; } - - -void SpiMaster::irq() { +void SpiMaster::irqStarted() { if(busy) { - if(bufferSize > 0) { - auto currentSize = std::min((size_t)255, bufferSize); + auto s = currentBufferSize; + if(s > 0) { + auto currentSize = std::min((size_t)255, s); - NRF_SPIM0->TXD.PTR = (uint32_t) bufferAddr; + NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr; NRF_SPIM0->TXD.MAXCNT = currentSize; NRF_SPIM0->TXD.LIST = 0; - bufferAddr += currentSize; - bufferSize -= currentSize; + currentBufferAddr += currentSize; + currentBufferSize -= currentSize; NRF_SPIM0->RXD.PTR = (uint32_t) 0; NRF_SPIM0->RXD.MAXCNT = 0; NRF_SPIM0->RXD.LIST = 0; - NRF_SPIM0->TASKS_START = 1; + + if(repeat == 0) + NRF_SPIM0->SHORTS = 0; return; }else { + if(repeat > 0) { + repeat = repeat -1; + + currentBufferAddr = bufferAddr; + currentBufferSize = bufferSize; + s = currentBufferSize; + auto currentSize = std::min((size_t)255, s); + NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr; + NRF_SPIM0->TXD.MAXCNT = currentSize; + NRF_SPIM0->TXD.LIST = 0; + + currentBufferAddr += currentSize; + currentBufferSize -= currentSize; + + NRF_SPIM0->RXD.PTR = (uint32_t) 0; + NRF_SPIM0->RXD.MAXCNT = 0; + NRF_SPIM0->RXD.LIST = 0; + } + } + } +} + +void SpiMaster::irqEnd() { + if(busy) { + if(repeat == 0 && currentBufferSize == 0) { nrf_gpio_pin_set(pinCsn); busy = false; } } } -bool SpiMaster::Write(const uint8_t *data, size_t size) { + +bool SpiMaster::Write(const uint8_t *data, size_t size, size_t r) { if(data == nullptr) return false; while(busy) { @@ -121,7 +149,7 @@ bool SpiMaster::Write(const uint8_t *data, size_t size) { setup_workaround_for_ftpan_58(NRF_SPIM0, 0,0); NRF_SPIM0->INTENCLR = (1<<6); NRF_SPIM0->INTENCLR = (1<<1); - + NRF_SPIM0->INTENCLR = (1<<19); } else { NRF_GPIOTE->CONFIG[0] = 0; NRF_PPI->CH[0].EEP = 0; @@ -129,38 +157,38 @@ bool SpiMaster::Write(const uint8_t *data, size_t size) { NRF_PPI->CHENSET = 0; NRF_SPIM0->INTENSET = (1<<6); NRF_SPIM0->INTENSET = (1<<1); + NRF_SPIM0->INTENSET = (1<<19); } nrf_gpio_pin_clear(pinCsn); - bufferAddr = (uint32_t)data; - bufferSize = size; + currentBufferAddr = bufferAddr = (uint32_t)data; + currentBufferSize = bufferSize = size; + repeat = r; busy = true; -// while(size > 0) { - auto currentSize = std::min((size_t)255, bufferSize); - NRF_SPIM0->TXD.PTR = (uint32_t) data; - NRF_SPIM0->TXD.MAXCNT = currentSize; - NRF_SPIM0->TXD.LIST = 0; + if(repeat > 0) + NRF_SPIM0->SHORTS = (1<<17); - bufferSize -= currentSize; - bufferAddr += currentSize; + auto currentSize = std::min((size_t)255, bufferSize); + NRF_SPIM0->TXD.PTR = bufferAddr; + NRF_SPIM0->TXD.MAXCNT = currentSize; + NRF_SPIM0->TXD.LIST = 0; - NRF_SPIM0->RXD.PTR = (uint32_t) 0; - NRF_SPIM0->RXD.MAXCNT = 0; - NRF_SPIM0->RXD.LIST = 0; + currentBufferSize -= currentSize; + currentBufferAddr += currentSize; - if(size != 1) { - NRF_SPIM0->EVENTS_END = 0; - } + NRF_SPIM0->RXD.PTR = (uint32_t) 0; + NRF_SPIM0->RXD.MAXCNT = 0; + NRF_SPIM0->RXD.LIST = 0; + NRF_SPIM0->EVENTS_END = 0; + NRF_SPIM0->TASKS_START = 1; - NRF_SPIM0->TASKS_START = 1; - - if(size == 1) { - while (NRF_SPIM0->EVENTS_END == 0); - busy = false; - nrf_gpio_pin_set(pinCsn); - } + if(size == 1) { + while (NRF_SPIM0->EVENTS_END == 0); + busy = false; + nrf_gpio_pin_set(pinCsn); + } return true; @@ -187,3 +215,9 @@ void SpiMaster::Sleep() { void SpiMaster::Wakeup() { Init(); } + +void SpiMaster::Wait() { + while(busy) { + asm("nop"); + } +} diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index dff63e94..ee03186c 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -23,9 +23,9 @@ namespace Pinetime { SpiMaster(const SpiModule spi, const Parameters& params); bool Init(); - bool Write(const uint8_t* data, size_t size); - bool WriteRepeat(const uint8_t *data, size_t size, int repeat); + bool Write(const uint8_t* data, size_t size, size_t r = 0); void setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); + void Wait(); void Sleep(); void Wakeup(); @@ -33,7 +33,8 @@ namespace Pinetime { bool GetStatusEnd(); bool GetStatusStarted(); - void irq(); + void irqEnd(); + void irqStarted(); private: NRF_SPIM_Type * spiBaseAddress; @@ -42,11 +43,13 @@ namespace Pinetime { SpiMaster::SpiModule spi; SpiMaster::Parameters params; - std::atomic busy {false}; + volatile bool busy = false; uint32_t bufferAddr = 0; - + volatile uint32_t currentBufferAddr = 0; size_t bufferSize = 0; + volatile size_t currentBufferSize = 0; + volatile uint32_t repeat = 0; }; } } diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index f47c2f58..6b663132 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -37,8 +37,8 @@ void St7789::WriteData(uint8_t data) { } -void St7789::WriteSpi(const uint8_t* data, size_t size) { - spi.Write(data, size); +void St7789::WriteSpi(const uint8_t* data, size_t size, size_t repeat) { + spi.Write(data, size, repeat); } void St7789::SoftwareReset() { @@ -143,10 +143,11 @@ void St7789::BeginDrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t he } void St7789::EndDrawBuffer() { + spi.Wait(); } -void St7789::NextDrawBuffer(const uint8_t *data, size_t size) { - WriteSpi(data, size); +void St7789::NextDrawBuffer(const uint8_t *data, size_t size, size_t repeat) { + WriteSpi(data, size, repeat); } void St7789::HardwareReset() { diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 8e4690b0..eef051b7 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -12,7 +12,7 @@ namespace Pinetime { void DrawPixel(uint16_t x, uint16_t y, uint32_t color); void BeginDrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height); - void NextDrawBuffer(const uint8_t* data, size_t size); + void NextDrawBuffer(const uint8_t* data, size_t size, size_t repeat = 0); void EndDrawBuffer(); void DisplayOn(); @@ -40,7 +40,7 @@ namespace Pinetime { void SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); void WriteCommand(uint8_t cmd); - void WriteSpi(const uint8_t* data, size_t size); + void WriteSpi(const uint8_t* data, size_t size, size_t repeat = 0); enum class Commands : uint8_t { SoftwareReset = 0x01, diff --git a/src/main.cpp b/src/main.cpp index 14be5ca2..284113c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -162,7 +162,12 @@ extern Pinetime::Drivers::SpiMaster* spiInstance; void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) { if(((NRF_SPIM0->INTENSET & (1<<6)) != 0) && NRF_SPIM0->EVENTS_END == 1) { NRF_SPIM0->EVENTS_END = 0; - spiInstance->irq(); + spiInstance->irqEnd(); + } + + if(((NRF_SPIM0->INTENSET & (1<<19)) != 0) && NRF_SPIM0->EVENTS_STARTED == 1) { + NRF_SPIM0->EVENTS_STARTED = 0; + spiInstance->irqStarted(); } diff --git a/src/sdk_config.h b/src/sdk_config.h index 21363202..e74751ef 100644 --- a/src/sdk_config.h +++ b/src/sdk_config.h @@ -8452,15 +8452,15 @@ // NRF_LOG_ENABLED - nrf_log - Logger //========================================================== #ifndef NRF_LOG_ENABLED -#define NRF_LOG_ENABLED 0 +#define NRF_LOG_ENABLED 1 #endif #ifndef NRF_LOG_BACKEND_RTT_ENABLED -#define NRF_LOG_BACKEND_RTT_ENABLED 0 +#define NRF_LOG_BACKEND_RTT_ENABLED 1 #endif #ifndef NRF_LOG_BACKEND_SERIAL_USES_RTT -#define NRF_LOG_BACKEND_SERIAL_USES_RTT 0 +#define NRF_LOG_BACKEND_SERIAL_USES_RTT 1 #endif // Log message pool - Configuration of log message pool From 5fa4f5abe0b752bb2d990378e02d6424a1d1b661 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 26 Jan 2020 13:37:10 +0100 Subject: [PATCH 4/6] Better integration of SPI with DMA and IRQ. Using only 'End' IRQ. Perf could be improved by using 'Started' IRQ to prepare the next buffer while the current one is beeing sent. --- src/Components/Gfx/Gfx.cpp | 102 +++++++++++++++++++++++++--------- src/Components/Gfx/Gfx.h | 18 +++++- src/DisplayApp/DisplayApp.cpp | 45 +++++++-------- src/DisplayApp/DisplayApp.h | 17 +++--- src/drivers/BufferProvider.h | 11 ++++ src/drivers/SpiMaster.cpp | 101 +++++++++++++-------------------- src/drivers/SpiMaster.h | 21 +++---- src/drivers/St7789.cpp | 14 ++--- src/drivers/St7789.h | 11 +--- src/main.cpp | 47 +++++++++++++--- 10 files changed, 223 insertions(+), 164 deletions(-) create mode 100644 src/drivers/BufferProvider.h diff --git a/src/Components/Gfx/Gfx.cpp b/src/Components/Gfx/Gfx.cpp index 94106513..2f64596c 100644 --- a/src/Components/Gfx/Gfx.cpp +++ b/src/Components/Gfx/Gfx.cpp @@ -7,23 +7,33 @@ Gfx::Gfx(Pinetime::Drivers::St7789 &lcd) : lcd{lcd} { } void Gfx::Init() { - lcd.Init(); + } void Gfx::ClearScreen() { SetBackgroundColor(0x0000); + + state.remainingIterations = 240 + 1; + state.currentIteration = 0; + state.busy = true; + state.action = Action::FillRectangle; + lcd.BeginDrawBuffer(0, 0, width, height); - for(int i = 0; i < height; i++) { - lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2); - } - lcd.EndDrawBuffer(); + lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2); + while(state.busy) {} // TODO wait on an event/queue/... instead of polling } -void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color) { +void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) { SetBackgroundColor(color); - lcd.BeginDrawBuffer(0, 0, width, height); - lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2, 240); - lcd.EndDrawBuffer(); + + state.remainingIterations = 240 + 1; + state.currentIteration = 0; + state.busy = true; + state.action = Action::FillRectangle; + + lcd.BeginDrawBuffer(x, y, w, h); + lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2); + while(state.busy) {} // TODO wait on an event/queue/... instead of polling } void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) { @@ -64,31 +74,37 @@ void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, con void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color) { uint8_t char_idx = c - font->startChar; uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8); + uint16_t bg = 0x0000; if (c == ' ') { *x += font->height / 2; return; } - // TODO For now, LCD and SPI driver start a new transfer (cs pin + set address windows + write byte) FOR EACH PIXEL! - // This could be improved by setting CS pin, DC pin and address window ONLY ONCE for the whole character - - lcd.BeginDrawBuffer(*x, y, bytes_in_line*8, font->height); - uint16_t bg = 0x0000; - for (uint16_t i = 0; i < font->height; i++) { - for (uint16_t j = 0; j < bytes_in_line; j++) { - for (uint8_t k = 0; k < 8; k++) { - if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + i * bytes_in_line + j]) { - buffer[(j*8)+k] = color; - } - else { - buffer[(j*8)+k] = bg; - } + // Build first line + for (uint16_t j = 0; j < bytes_in_line; j++) { + for (uint8_t k = 0; k < 8; k++) { + if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) { + buffer[(j*8)+k] = color; + } + else { + buffer[(j*8)+k] = bg; } } - lcd.NextDrawBuffer(reinterpret_cast(&buffer), bytes_in_line*8*2); } - lcd.EndDrawBuffer(); + + state.remainingIterations = font->height + 0; + state.currentIteration = 0; + state.busy = true; + state.action = Action::DrawChar; + state.font = const_cast(font); + state.character = c; + state.color = color; + + lcd.BeginDrawBuffer(*x, y, bytes_in_line*8, font->height); + lcd.NextDrawBuffer(reinterpret_cast(&buffer), bytes_in_line*8*2); + while(state.busy) {} // TODO wait on an event/queue/... instead of polling + *x += font->charInfo[char_idx].widthBits + font->spacePixels; } @@ -110,4 +126,40 @@ void Gfx::SetBackgroundColor(uint16_t color) { } } +bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) { + if(!state.busy) return false; + state.remainingIterations--; + if (state.remainingIterations == 0) { + state.busy = false; + return false; + } + + if(state.action == Action::FillRectangle) { + *data = reinterpret_cast(buffer); + size = width * 2; + } else if(state.action == Action::DrawChar) { + uint16_t bg = 0x0000; + uint8_t char_idx = state.character - state.font->startChar; + uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8); + + for (uint16_t j = 0; j < bytes_in_line; j++) { + for (uint8_t k = 0; k < 8; k++) { + if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration+1) * bytes_in_line) + j]) { + buffer[(j*8)+k] = state.color; + } + else { + buffer[(j*8)+k] = bg; + } + } + } + + *data = reinterpret_cast(buffer); + size = bytes_in_line*8*2; + } + + state.currentIteration++; + + return true; +} + diff --git a/src/Components/Gfx/Gfx.h b/src/Components/Gfx/Gfx.h index d8728701..81c5f387 100644 --- a/src/Components/Gfx/Gfx.h +++ b/src/Components/Gfx/Gfx.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace Pinetime { @@ -8,7 +9,7 @@ namespace Pinetime { class St7789; } namespace Components { - class Gfx { + class Gfx : public Pinetime::Drivers::BufferProvider { public: explicit Gfx(Drivers::St7789& lcd); void Init(); @@ -19,11 +20,26 @@ namespace Pinetime { void Sleep(); void Wakeup(); + bool GetNextBuffer(uint8_t **buffer, size_t &size) override; private: static constexpr uint8_t width = 240; static constexpr uint8_t height = 240; + enum class Action { None, FillRectangle, DrawChar}; + struct State { + State() : busy{false}, action{Action::None}, remainingIterations{0}, currentIteration{0} {} + volatile bool busy; + volatile Action action; + volatile uint16_t remainingIterations; + volatile uint16_t currentIteration; + volatile FONT_INFO *font; + volatile uint16_t color; + volatile uint8_t character; + }; + + volatile State state; + uint16_t buffer[width]; // 1 line buffer Drivers::St7789& lcd; diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index c1561cc2..8795416c 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -14,25 +14,20 @@ using namespace Pinetime::Applications; -DisplayApp::DisplayApp(Controllers::Battery &batteryController, +DisplayApp::DisplayApp(Pinetime::Drivers::St7789& lcd, + Pinetime::Components::Gfx& gfx, + Pinetime::Drivers::Cst816S& touchPanel, + Controllers::Battery &batteryController, Controllers::Ble &bleController, Controllers::DateTime &dateTimeController) : - spi{Drivers::SpiMaster::SpiModule::SPI0, { - Drivers::SpiMaster::BitOrder::Msb_Lsb, - Drivers::SpiMaster::Modes::Mode3, - Drivers::SpiMaster::Frequencies::Freq8Mhz, - pinSpiSck, - pinSpiMosi, - pinSpiMiso, - pinSpiCsn - }}, - lcd{new Drivers::St7789(spi, pinLcdDataCommand)}, - gfx{new Components::Gfx(*lcd.get()) }, + lcd{lcd}, + gfx{gfx}, + touchPanel{touchPanel}, batteryController{batteryController}, bleController{bleController}, dateTimeController{dateTimeController}, - clockScreen{*(gfx.get())}, - messageScreen{*(gfx.get())} { + clockScreen{gfx}, + messageScreen{gfx} { msgQueue = xQueueCreate(queueSize, itemSize); currentScreen = &clockScreen; } @@ -59,22 +54,19 @@ void DisplayApp::InitHw() { nrf_gpio_pin_clear(pinLcdBacklight2); nrf_gpio_pin_clear(pinLcdBacklight3); - spi.Init(); - gfx->Init(); currentScreen->Refresh(true); - touchPanel.Init(); } uint32_t acc = 0; uint32_t count = 0; bool toggle = true; void DisplayApp::Refresh() { - +#if 0 uint32_t before = nrf_rtc_counter_get(portNRF_RTC_REG); if(toggle) { - gfx->FillRectangle(0,0,240,240,0x0000); + gfx.FillRectangle(0,0,240,240,0x0000); } else { - gfx->FillRectangle(0,0,240,240,0xffff); + gfx.FillRectangle(0,0,240,240,0xffff); } uint32_t after = nrf_rtc_counter_get(portNRF_RTC_REG); @@ -85,8 +77,9 @@ void DisplayApp::Refresh() { } count++; toggle = !toggle; +#endif -#if 0 +#if 1 TickType_t queueTimeout; switch (state) { case States::Idle: @@ -108,16 +101,16 @@ void DisplayApp::Refresh() { nrf_gpio_pin_set(pinLcdBacklight2); vTaskDelay(100); nrf_gpio_pin_set(pinLcdBacklight1); - lcd->DisplayOff(); - lcd->Sleep(); + lcd.DisplayOff(); + lcd.Sleep(); touchPanel.Sleep(); state = States::Idle; break; case Messages::GoToRunning: - lcd->Wakeup(); + lcd.Wakeup(); touchPanel.Wakeup(); - lcd->DisplayOn(); + lcd.DisplayOn(); nrf_gpio_pin_clear(pinLcdBacklight3); nrf_gpio_pin_clear(pinLcdBacklight2); nrf_gpio_pin_clear(pinLcdBacklight1); @@ -179,7 +172,7 @@ void DisplayApp::OnTouchEvent() { auto info = touchPanel.GetTouchInfo(); if(info.isTouch) { - gfx->FillRectangle(info.x-10, info.y-10, 20,20, pointColor); + gfx.FillRectangle(info.x-10, info.y-10, 20,20, pointColor); pointColor+=10; } } diff --git a/src/DisplayApp/DisplayApp.h b/src/DisplayApp/DisplayApp.h index eabfe099..04265426 100644 --- a/src/DisplayApp/DisplayApp.h +++ b/src/DisplayApp/DisplayApp.h @@ -23,7 +23,10 @@ namespace Pinetime { public: enum class States {Idle, Running}; enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent} ; - DisplayApp(Controllers::Battery &batteryController, + DisplayApp(Pinetime::Drivers::St7789& lcd, + Pinetime::Components::Gfx& gfx, + Pinetime::Drivers::Cst816S&, + Controllers::Battery &batteryController, Controllers::Ble &bleController, Controllers::DateTime& dateTimeController); void Start(); @@ -33,9 +36,8 @@ namespace Pinetime { TaskHandle_t taskHandle; static void Process(void* instance); void InitHw(); - Pinetime::Drivers::SpiMaster spi; - std::unique_ptr lcd; - std::unique_ptr gfx; + Pinetime::Drivers::St7789& lcd; + Pinetime::Components::Gfx& gfx; const FONT_INFO largeFont {lCD_70ptFontInfo.height, lCD_70ptFontInfo.startChar, lCD_70ptFontInfo.endChar, lCD_70ptFontInfo.spacePixels, lCD_70ptFontInfo.charInfo, lCD_70ptFontInfo.data}; const FONT_INFO smallFont {lCD_14ptFontInfo.height, lCD_14ptFontInfo.startChar, lCD_14ptFontInfo.endChar, lCD_14ptFontInfo.spacePixels, lCD_14ptFontInfo.charInfo, lCD_14ptFontInfo.data}; void Refresh(); @@ -52,18 +54,13 @@ namespace Pinetime { Pinetime::Controllers::Ble &bleController; Pinetime::Controllers::DateTime& dateTimeController; - Pinetime::Drivers::Cst816S touchPanel; + Pinetime::Drivers::Cst816S& touchPanel; void OnTouchEvent(); Screens::Clock clockScreen; Screens::Screen* currentScreen = nullptr; Screens::Message messageScreen; bool screenState = false; - static constexpr uint8_t pinSpiSck = 2; - static constexpr uint8_t pinSpiMosi = 3; - static constexpr uint8_t pinSpiMiso = 4; - static constexpr uint8_t pinSpiCsn = 25; - static constexpr uint8_t pinLcdDataCommand = 18; static constexpr uint8_t pinLcdBacklight1 = 14; static constexpr uint8_t pinLcdBacklight2 = 22; static constexpr uint8_t pinLcdBacklight3 = 23; diff --git a/src/drivers/BufferProvider.h b/src/drivers/BufferProvider.h new file mode 100644 index 00000000..50fa253e --- /dev/null +++ b/src/drivers/BufferProvider.h @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace Pinetime { + namespace Drivers { + class BufferProvider { + public: + virtual bool GetNextBuffer(uint8_t** buffer, size_t& size) = 0; + }; + } +} \ No newline at end of file diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 7c6186a6..84243a96 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -4,10 +4,9 @@ #include using namespace Pinetime::Drivers; -SpiMaster* spiInstance; SpiMaster::SpiMaster(const SpiMaster::SpiModule spi, const SpiMaster::Parameters ¶ms) : spi{spi}, params{params} { - spiInstance = this; + } bool SpiMaster::Init() { @@ -84,12 +83,33 @@ void SpiMaster::setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_ NRF_PPI->CHENSET = 1U << ppi_channel; } -void SpiMaster::irqStarted() { - if(busy) { - auto s = currentBufferSize; - if(s > 0) { - auto currentSize = std::min((size_t)255, s); +void SpiMaster::OnEndEvent(BufferProvider& provider) { + if(!busy) return; + auto s = currentBufferSize; + if(s > 0) { + auto currentSize = std::min((size_t) 255, s); + + NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr; + NRF_SPIM0->TXD.MAXCNT = currentSize; + NRF_SPIM0->TXD.LIST = 0; + + currentBufferAddr += currentSize; + currentBufferSize -= currentSize; + + NRF_SPIM0->RXD.PTR = (uint32_t) 0; + NRF_SPIM0->RXD.MAXCNT = 0; + NRF_SPIM0->RXD.LIST = 0; + + NRF_SPIM0->TASKS_START = 1; + } else { + uint8_t* buffer = nullptr; + size_t size = 0; + if(provider.GetNextBuffer(&buffer, size)) { + currentBufferAddr = (uint32_t) buffer; + currentBufferSize = size; + auto s = currentBufferSize; + auto currentSize = std::min((size_t)255, s); NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr; NRF_SPIM0->TXD.MAXCNT = currentSize; NRF_SPIM0->TXD.LIST = 0; @@ -101,44 +121,19 @@ void SpiMaster::irqStarted() { NRF_SPIM0->RXD.MAXCNT = 0; NRF_SPIM0->RXD.LIST = 0; - if(repeat == 0) - NRF_SPIM0->SHORTS = 0; - - return; - }else { - if(repeat > 0) { - repeat = repeat -1; - - currentBufferAddr = bufferAddr; - currentBufferSize = bufferSize; - s = currentBufferSize; - auto currentSize = std::min((size_t)255, s); - NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr; - NRF_SPIM0->TXD.MAXCNT = currentSize; - NRF_SPIM0->TXD.LIST = 0; - - currentBufferAddr += currentSize; - currentBufferSize -= currentSize; - - NRF_SPIM0->RXD.PTR = (uint32_t) 0; - NRF_SPIM0->RXD.MAXCNT = 0; - NRF_SPIM0->RXD.LIST = 0; - } - } - } -} - -void SpiMaster::irqEnd() { - if(busy) { - if(repeat == 0 && currentBufferSize == 0) { - nrf_gpio_pin_set(pinCsn); + NRF_SPIM0->TASKS_START = 1; + } else { busy = false; + nrf_gpio_pin_set(pinCsn); } } } +void SpiMaster::OnStartedEvent(BufferProvider& provider) { + if(!busy) return; +} -bool SpiMaster::Write(const uint8_t *data, size_t size, size_t r) { +bool SpiMaster::Write(const uint8_t *data, size_t size) { if(data == nullptr) return false; while(busy) { @@ -162,16 +157,12 @@ bool SpiMaster::Write(const uint8_t *data, size_t size, size_t r) { nrf_gpio_pin_clear(pinCsn); - currentBufferAddr = bufferAddr = (uint32_t)data; - currentBufferSize = bufferSize = size; - repeat = r; + currentBufferAddr = (uint32_t)data; + currentBufferSize = size; busy = true; - if(repeat > 0) - NRF_SPIM0->SHORTS = (1<<17); - - auto currentSize = std::min((size_t)255, bufferSize); - NRF_SPIM0->TXD.PTR = bufferAddr; + auto currentSize = std::min((size_t)255, (size_t)currentBufferSize); + NRF_SPIM0->TXD.PTR = currentBufferAddr; NRF_SPIM0->TXD.MAXCNT = currentSize; NRF_SPIM0->TXD.LIST = 0; @@ -187,21 +178,11 @@ bool SpiMaster::Write(const uint8_t *data, size_t size, size_t r) { if(size == 1) { while (NRF_SPIM0->EVENTS_END == 0); busy = false; - nrf_gpio_pin_set(pinCsn); } - return true; } -bool SpiMaster::GetStatusEnd() { - return (bool)*(volatile uint32_t *)((uint8_t *)spiBaseAddress + (uint32_t)NRF_SPIM_EVENT_END); -} - -bool SpiMaster::GetStatusStarted() { - return (bool)*(volatile uint32_t *)((uint8_t *)spiBaseAddress + (uint32_t)NRF_SPIM_EVENT_STARTED); -} - void SpiMaster::Sleep() { while(NRF_SPIM0->ENABLE != 0) { NRF_SPIM0->ENABLE = (SPIM_ENABLE_ENABLE_Disabled << SPIM_ENABLE_ENABLE_Pos); @@ -216,8 +197,4 @@ void SpiMaster::Wakeup() { Init(); } -void SpiMaster::Wait() { - while(busy) { - asm("nop"); - } -} + diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index ee03186c..7dac747a 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -3,6 +3,8 @@ #include #include #include + +#include "BufferProvider.h" namespace Pinetime { namespace Drivers { class SpiMaster { @@ -23,20 +25,17 @@ namespace Pinetime { SpiMaster(const SpiModule spi, const Parameters& params); bool Init(); - bool Write(const uint8_t* data, size_t size, size_t r = 0); - void setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); - void Wait(); + bool Write(const uint8_t* data, size_t size); + + void OnStartedEvent(BufferProvider& provider); + void OnEndEvent(BufferProvider& provider); void Sleep(); void Wakeup(); - bool GetStatusEnd(); - bool GetStatusStarted(); - - void irqEnd(); - void irqStarted(); - private: + void setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); + NRF_SPIM_Type * spiBaseAddress; uint8_t pinCsn; @@ -44,12 +43,8 @@ namespace Pinetime { SpiMaster::Parameters params; volatile bool busy = false; - - uint32_t bufferAddr = 0; volatile uint32_t currentBufferAddr = 0; - size_t bufferSize = 0; volatile size_t currentBufferSize = 0; - volatile uint32_t repeat = 0; }; } } diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index 6b663132..39595dc9 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -37,8 +37,8 @@ void St7789::WriteData(uint8_t data) { } -void St7789::WriteSpi(const uint8_t* data, size_t size, size_t repeat) { - spi.Write(data, size, repeat); +void St7789::WriteSpi(const uint8_t* data, size_t size) { + spi.Write(data, size); } void St7789::SoftwareReset() { @@ -142,12 +142,8 @@ void St7789::BeginDrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t he nrf_gpio_pin_set(pinDataCommand); } -void St7789::EndDrawBuffer() { - spi.Wait(); -} - -void St7789::NextDrawBuffer(const uint8_t *data, size_t size, size_t repeat) { - WriteSpi(data, size, repeat); +void St7789::NextDrawBuffer(const uint8_t *data, size_t size) { + WriteSpi(data, size); } void St7789::HardwareReset() { @@ -178,5 +174,3 @@ void St7789::Wakeup() { NormalModeOn(); DisplayOn(); } - - diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index eef051b7..9ecf9f27 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -12,16 +12,13 @@ namespace Pinetime { void DrawPixel(uint16_t x, uint16_t y, uint32_t color); void BeginDrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height); - void NextDrawBuffer(const uint8_t* data, size_t size, size_t repeat = 0); - void EndDrawBuffer(); + void NextDrawBuffer(const uint8_t* data, size_t size); void DisplayOn(); void DisplayOff(); void Sleep(); void Wakeup(); - - private: SpiMaster& spi; uint8_t pinDataCommand; @@ -35,12 +32,9 @@ namespace Pinetime { void DisplayInversionOn(); void NormalModeOn(); void WriteToRam(); - - void SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); - void WriteCommand(uint8_t cmd); - void WriteSpi(const uint8_t* data, size_t size, size_t repeat = 0); + void WriteSpi(const uint8_t* data, size_t size); enum class Commands : uint8_t { SoftwareReset = 0x01, @@ -62,7 +56,6 @@ namespace Pinetime { static constexpr uint16_t Width = 240; static constexpr uint16_t Height = 240; void RowAddressSet(); - }; } } diff --git a/src/main.cpp b/src/main.cpp index 284113c1..13dddca6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,10 @@ #include "BLE/BleManager.h" #include "Components/Battery/BatteryController.h" #include "Components/Ble/BleController.h" +#include "../drivers/Cst816s.h" +#include +#include +#include #if NRF_LOG_ENABLED #include "Logging/NrfLogger.h" @@ -24,6 +28,18 @@ Pinetime::Logging::NrfLogger logger; Pinetime::Logging::DummyLogger logger; #endif +std::unique_ptr spi; +std::unique_ptr lcd; +std::unique_ptr gfx; +std::unique_ptr touchPanel; + +static constexpr uint8_t pinSpiSck = 2; +static constexpr uint8_t pinSpiMosi = 3; +static constexpr uint8_t pinSpiMiso = 4; +static constexpr uint8_t pinSpiCsn = 25; +static constexpr uint8_t pinLcdDataCommand = 18; + + std::unique_ptr displayApp; TaskHandle_t systemThread; bool isSleeping = false; @@ -85,9 +101,29 @@ void SystemTask(void *) { APP_GPIOTE_INIT(2); bool erase_bonds=false; nrf_sdh_freertos_init(ble_manager_start_advertising, &erase_bonds); + + spi.reset(new Pinetime::Drivers::SpiMaster {Pinetime::Drivers::SpiMaster::SpiModule::SPI0, { + Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb, + Pinetime::Drivers::SpiMaster::Modes::Mode3, + Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz, + pinSpiSck, + pinSpiMosi, + pinSpiMiso, + pinSpiCsn + }}); + + lcd.reset(new Pinetime::Drivers::St7789(*spi, pinLcdDataCommand)); + gfx.reset(new Pinetime::Components::Gfx(*lcd)); + touchPanel.reset(new Pinetime::Drivers::Cst816S()); + + spi->Init(); + lcd->Init(); + touchPanel->Init(); + batteryController.Init(); + + displayApp.reset(new Pinetime::Applications::DisplayApp(*lcd, *gfx, *touchPanel, batteryController, bleController, dateTimeController)); displayApp->Start(); - batteryController.Init(); batteryController.Update(); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::UpdateBatteryLevel); @@ -158,27 +194,22 @@ void OnNewTime(current_time_char_t* currentTime) { dayOfWeek, hour, minute, second, nrf_rtc_counter_get(portNRF_RTC_REG)); } -extern Pinetime::Drivers::SpiMaster* spiInstance; void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) { if(((NRF_SPIM0->INTENSET & (1<<6)) != 0) && NRF_SPIM0->EVENTS_END == 1) { NRF_SPIM0->EVENTS_END = 0; - spiInstance->irqEnd(); + spi->OnEndEvent(*gfx); } if(((NRF_SPIM0->INTENSET & (1<<19)) != 0) && NRF_SPIM0->EVENTS_STARTED == 1) { NRF_SPIM0->EVENTS_STARTED = 0; - spiInstance->irqStarted(); + spi->OnStartedEvent(*gfx); } - if(((NRF_SPIM0->INTENSET & (1<<1)) != 0) && NRF_SPIM0->EVENTS_STOPPED == 1) { NRF_SPIM0->EVENTS_STOPPED = 0; } - - return; } int main(void) { - displayApp.reset(new Pinetime::Applications::DisplayApp(batteryController, bleController, dateTimeController)); logger.Init(); nrf_drv_clock_init(); From 640e8cd1febc679b976fb26225aec8d462a4c241 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 26 Jan 2020 15:35:18 +0100 Subject: [PATCH 5/6] GFX : wait end of transfert using a task notification. Code cleaning in SpiMaster. --- src/Components/Gfx/Gfx.cpp | 27 ++++++++- src/Components/Gfx/Gfx.h | 5 ++ src/drivers/SpiMaster.cpp | 109 +++++++++++++++++-------------------- src/drivers/SpiMaster.h | 4 +- 4 files changed, 82 insertions(+), 63 deletions(-) diff --git a/src/Components/Gfx/Gfx.cpp b/src/Components/Gfx/Gfx.cpp index 2f64596c..0dcb98a6 100644 --- a/src/Components/Gfx/Gfx.cpp +++ b/src/Components/Gfx/Gfx.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "Gfx.h" #include "../../drivers/St7789.h" using namespace Pinetime::Components; @@ -17,10 +19,12 @@ void Gfx::ClearScreen() { state.currentIteration = 0; state.busy = true; state.action = Action::FillRectangle; + state.taskToNotify = xTaskGetCurrentTaskHandle(); lcd.BeginDrawBuffer(0, 0, width, height); lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2); - while(state.busy) {} // TODO wait on an event/queue/... instead of polling + WaitTransfertFinished(); + } void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) { @@ -30,10 +34,13 @@ void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t col state.currentIteration = 0; state.busy = true; state.action = Action::FillRectangle; + state.color = color; + state.taskToNotify = xTaskGetCurrentTaskHandle(); lcd.BeginDrawBuffer(x, y, w, h); lcd.NextDrawBuffer(reinterpret_cast(buffer), width * 2); - while(state.busy) {} // TODO wait on an event/queue/... instead of polling + + WaitTransfertFinished(); } void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) { @@ -100,10 +107,11 @@ void Gfx::DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint state.font = const_cast(font); state.character = c; state.color = color; + state.taskToNotify = xTaskGetCurrentTaskHandle(); lcd.BeginDrawBuffer(*x, y, bytes_in_line*8, font->height); lcd.NextDrawBuffer(reinterpret_cast(&buffer), bytes_in_line*8*2); - while(state.busy) {} // TODO wait on an event/queue/... instead of polling + WaitTransfertFinished(); *x += font->charInfo[char_idx].widthBits + font->spacePixels; } @@ -131,6 +139,7 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) { state.remainingIterations--; if (state.remainingIterations == 0) { state.busy = false; + NotifyEndOfTransfert(state.taskToNotify); return false; } @@ -162,4 +171,16 @@ bool Gfx::GetNextBuffer(uint8_t **data, size_t &size) { return true; } +void Gfx::NotifyEndOfTransfert(TaskHandle_t task) { + if(task != nullptr) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } +} + +void Gfx::WaitTransfertFinished() const { + ulTaskNotifyTake(pdTRUE, 500); +} + diff --git a/src/Components/Gfx/Gfx.h b/src/Components/Gfx/Gfx.h index 81c5f387..f31b13c0 100644 --- a/src/Components/Gfx/Gfx.h +++ b/src/Components/Gfx/Gfx.h @@ -2,6 +2,8 @@ #include #include #include +#include +#include namespace Pinetime { @@ -36,6 +38,7 @@ namespace Pinetime { volatile FONT_INFO *font; volatile uint16_t color; volatile uint8_t character; + volatile TaskHandle_t taskToNotify = nullptr; }; volatile State state; @@ -45,6 +48,8 @@ namespace Pinetime { void pixel_draw(uint8_t x, uint8_t y, uint16_t color); void SetBackgroundColor(uint16_t color); + void WaitTransfertFinished() const; + void NotifyEndOfTransfert(TaskHandle_t task); }; } } diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 84243a96..4a875b9e 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -26,9 +26,9 @@ bool SpiMaster::Init() { } /* Configure pins, frequency and mode */ - NRF_SPIM0->PSELSCK = params.pinSCK; - NRF_SPIM0->PSELMOSI = params.pinMOSI; - NRF_SPIM0->PSELMISO = params.pinMISO; + spiBaseAddress->PSELSCK = params.pinSCK; + spiBaseAddress->PSELMOSI = params.pinMOSI; + spiBaseAddress->PSELMISO = params.pinMISO; nrf_gpio_pin_set(pinCsn); /* disable Set slave select (inactive high) */ uint32_t frequency; @@ -36,7 +36,7 @@ bool SpiMaster::Init() { case Frequencies::Freq8Mhz: frequency = 0x80000000; break; default: return false; } - NRF_SPIM0->FREQUENCY = frequency; + spiBaseAddress->FREQUENCY = frequency; uint32_t regConfig = 0; switch(params.bitOrder) { @@ -52,26 +52,24 @@ bool SpiMaster::Init() { default: return false; } - setup_workaround_for_ftpan_58(NRF_SPIM0, 0, 0); + spiBaseAddress->CONFIG = regConfig; + spiBaseAddress->EVENTS_ENDRX = 0; + spiBaseAddress->EVENTS_ENDTX = 0; + spiBaseAddress->EVENTS_END = 0; - NRF_SPIM0->CONFIG = regConfig; - NRF_SPIM0->EVENTS_ENDRX = 0; - NRF_SPIM0->EVENTS_ENDTX = 0; - NRF_SPIM0->EVENTS_END = 0; + spiBaseAddress->INTENSET = ((unsigned)1 << (unsigned)6); + spiBaseAddress->INTENSET = ((unsigned)1 << (unsigned)1); + spiBaseAddress->INTENSET = ((unsigned)1 << (unsigned)19); - NRF_SPIM0->INTENSET = ((unsigned)1 << (unsigned)6); - NRF_SPIM0->INTENSET = ((unsigned)1 << (unsigned)1); - NRF_SPIM0->INTENSET = ((unsigned)1 << (unsigned)19); + spiBaseAddress->ENABLE = (SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos); - NRF_SPIM0->ENABLE = (SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos); - - NRFX_IRQ_PRIORITY_SET(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn,6); + NRFX_IRQ_PRIORITY_SET(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn,2); NRFX_IRQ_ENABLE(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn); return true; } -void SpiMaster::setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel) { +void SpiMaster::SetupWorkaroundForFtpan58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel) { // Create an event when SCK toggles. NRF_GPIOTE->CONFIG[gpiote_channel] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | (spim->PSEL.SCK << GPIOTE_CONFIG_PSEL_Pos) | @@ -81,6 +79,21 @@ void SpiMaster::setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_ NRF_PPI->CH[ppi_channel].EEP = (uint32_t) &NRF_GPIOTE->EVENTS_IN[gpiote_channel]; NRF_PPI->CH[ppi_channel].TEP = (uint32_t) &spim->TASKS_STOP; NRF_PPI->CHENSET = 1U << ppi_channel; + + // Disable IRQ + spim->INTENCLR = (1<<6); + spim->INTENCLR = (1<<1); + spim->INTENCLR = (1<<19); +} + +void SpiMaster::DisableWorkaroundForFtpan58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel) { + NRF_GPIOTE->CONFIG[gpiote_channel] = 0; + NRF_PPI->CH[ppi_channel].EEP = 0; + NRF_PPI->CH[ppi_channel].TEP = 0; + NRF_PPI->CHENSET = ppi_channel; + spim->INTENSET = (1<<6); + spim->INTENSET = (1<<1); + spim->INTENSET = (1<<19); } void SpiMaster::OnEndEvent(BufferProvider& provider) { @@ -89,19 +102,11 @@ void SpiMaster::OnEndEvent(BufferProvider& provider) { auto s = currentBufferSize; if(s > 0) { auto currentSize = std::min((size_t) 255, s); - - NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr; - NRF_SPIM0->TXD.MAXCNT = currentSize; - NRF_SPIM0->TXD.LIST = 0; - + PrepareTx(currentBufferAddr, currentSize); currentBufferAddr += currentSize; currentBufferSize -= currentSize; - NRF_SPIM0->RXD.PTR = (uint32_t) 0; - NRF_SPIM0->RXD.MAXCNT = 0; - NRF_SPIM0->RXD.LIST = 0; - - NRF_SPIM0->TASKS_START = 1; + spiBaseAddress->TASKS_START = 1; } else { uint8_t* buffer = nullptr; size_t size = 0; @@ -110,18 +115,11 @@ void SpiMaster::OnEndEvent(BufferProvider& provider) { currentBufferSize = size; auto s = currentBufferSize; auto currentSize = std::min((size_t)255, s); - NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr; - NRF_SPIM0->TXD.MAXCNT = currentSize; - NRF_SPIM0->TXD.LIST = 0; - + PrepareTx(currentBufferAddr, currentSize); currentBufferAddr += currentSize; currentBufferSize -= currentSize; - NRF_SPIM0->RXD.PTR = (uint32_t) 0; - NRF_SPIM0->RXD.MAXCNT = 0; - NRF_SPIM0->RXD.LIST = 0; - - NRF_SPIM0->TASKS_START = 1; + spiBaseAddress->TASKS_START = 1; } else { busy = false; nrf_gpio_pin_set(pinCsn); @@ -133,6 +131,16 @@ void SpiMaster::OnStartedEvent(BufferProvider& provider) { if(!busy) return; } +void SpiMaster::PrepareTx(const volatile uint32_t bufferAddress, const volatile size_t size) { + spiBaseAddress->TXD.PTR = bufferAddress; + spiBaseAddress->TXD.MAXCNT = size; + spiBaseAddress->TXD.LIST = 0; + spiBaseAddress->RXD.PTR = 0; + spiBaseAddress->RXD.MAXCNT = 0; + spiBaseAddress->RXD.LIST = 0; + spiBaseAddress->EVENTS_END = 0; +} + bool SpiMaster::Write(const uint8_t *data, size_t size) { if(data == nullptr) return false; @@ -141,18 +149,9 @@ bool SpiMaster::Write(const uint8_t *data, size_t size) { } if(size == 1) { - setup_workaround_for_ftpan_58(NRF_SPIM0, 0,0); - NRF_SPIM0->INTENCLR = (1<<6); - NRF_SPIM0->INTENCLR = (1<<1); - NRF_SPIM0->INTENCLR = (1<<19); + SetupWorkaroundForFtpan58(spiBaseAddress, 0,0); } else { - NRF_GPIOTE->CONFIG[0] = 0; - NRF_PPI->CH[0].EEP = 0; - NRF_PPI->CH[0].TEP = 0; - NRF_PPI->CHENSET = 0; - NRF_SPIM0->INTENSET = (1<<6); - NRF_SPIM0->INTENSET = (1<<1); - NRF_SPIM0->INTENSET = (1<<19); + DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); } nrf_gpio_pin_clear(pinCsn); @@ -162,21 +161,13 @@ bool SpiMaster::Write(const uint8_t *data, size_t size) { busy = true; auto currentSize = std::min((size_t)255, (size_t)currentBufferSize); - NRF_SPIM0->TXD.PTR = currentBufferAddr; - NRF_SPIM0->TXD.MAXCNT = currentSize; - NRF_SPIM0->TXD.LIST = 0; - + PrepareTx(currentBufferAddr, currentSize); currentBufferSize -= currentSize; currentBufferAddr += currentSize; - - NRF_SPIM0->RXD.PTR = (uint32_t) 0; - NRF_SPIM0->RXD.MAXCNT = 0; - NRF_SPIM0->RXD.LIST = 0; - NRF_SPIM0->EVENTS_END = 0; - NRF_SPIM0->TASKS_START = 1; + spiBaseAddress->TASKS_START = 1; if(size == 1) { - while (NRF_SPIM0->EVENTS_END == 0); + while (spiBaseAddress->EVENTS_END == 0); busy = false; } @@ -184,8 +175,8 @@ bool SpiMaster::Write(const uint8_t *data, size_t size) { } void SpiMaster::Sleep() { - while(NRF_SPIM0->ENABLE != 0) { - NRF_SPIM0->ENABLE = (SPIM_ENABLE_ENABLE_Disabled << SPIM_ENABLE_ENABLE_Pos); + while(spiBaseAddress->ENABLE != 0) { + spiBaseAddress->ENABLE = (SPIM_ENABLE_ENABLE_Disabled << SPIM_ENABLE_ENABLE_Pos); } nrf_gpio_cfg_default(params.pinSCK); nrf_gpio_cfg_default(params.pinMOSI); diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 7dac747a..60013242 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -34,7 +34,9 @@ namespace Pinetime { void Wakeup(); private: - void setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); + void SetupWorkaroundForFtpan58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); + void DisableWorkaroundForFtpan58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel); + void PrepareTx(const volatile uint32_t bufferAddress, const volatile size_t size); NRF_SPIM_Type * spiBaseAddress; uint8_t pinCsn; From 6491a7c3a0738d6e6ef3bf57da460f61298d1cd9 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 26 Jan 2020 15:39:49 +0100 Subject: [PATCH 6/6] Remove test code --- CMakeLists.txt | 2 +- src/DisplayApp/DisplayApp.cpp | 37 ++--------------------------------- src/DisplayApp/DisplayApp.h | 2 -- src/sdk_config.h | 6 +++--- 4 files changed, 6 insertions(+), 41 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21c63797..a8d8426b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(pinetime VERSION 0.2.99 LANGUAGES C CXX ASM) +project(pinetime VERSION 0.2.1 LANGUAGES C CXX ASM) set(NRF_TARGET "nrf52") diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index 8795416c..ca139423 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -26,8 +26,7 @@ DisplayApp::DisplayApp(Pinetime::Drivers::St7789& lcd, batteryController{batteryController}, bleController{bleController}, dateTimeController{dateTimeController}, - clockScreen{gfx}, - messageScreen{gfx} { + clockScreen{gfx} { msgQueue = xQueueCreate(queueSize, itemSize); currentScreen = &clockScreen; } @@ -61,25 +60,6 @@ uint32_t acc = 0; uint32_t count = 0; bool toggle = true; void DisplayApp::Refresh() { -#if 0 - uint32_t before = nrf_rtc_counter_get(portNRF_RTC_REG); - if(toggle) { - gfx.FillRectangle(0,0,240,240,0x0000); - } else { - gfx.FillRectangle(0,0,240,240,0xffff); - } - uint32_t after = nrf_rtc_counter_get(portNRF_RTC_REG); - - acc += (after - before); - if((count % 10) == 0) { - NRF_LOG_INFO("DRAW : %d ms", (uint32_t)(acc/10)); - acc = 0; - } - count++; - toggle = !toggle; -#endif - -#if 1 TickType_t queueTimeout; switch (state) { case States::Idle: @@ -130,29 +110,16 @@ void DisplayApp::Refresh() { break; } } -#endif } void DisplayApp::RunningState() { clockScreen.SetCurrentDateTime(dateTimeController.CurrentDateTime()); -// if(currentScreen != nullptr) { -// currentScreen->Refresh(false); -// } - if(currentScreen != nullptr) { - currentScreen->Refresh(true); + currentScreen->Refresh(false); } - - if(screenState) { - currentScreen = &clockScreen; - } else { - currentScreen = &messageScreen; - } - screenState = !screenState; } - void DisplayApp::IdleState() { } diff --git a/src/DisplayApp/DisplayApp.h b/src/DisplayApp/DisplayApp.h index 04265426..5a5d3ee6 100644 --- a/src/DisplayApp/DisplayApp.h +++ b/src/DisplayApp/DisplayApp.h @@ -59,8 +59,6 @@ namespace Pinetime { Screens::Clock clockScreen; Screens::Screen* currentScreen = nullptr; - Screens::Message messageScreen; - bool screenState = false; static constexpr uint8_t pinLcdBacklight1 = 14; static constexpr uint8_t pinLcdBacklight2 = 22; static constexpr uint8_t pinLcdBacklight3 = 23; diff --git a/src/sdk_config.h b/src/sdk_config.h index e74751ef..21363202 100644 --- a/src/sdk_config.h +++ b/src/sdk_config.h @@ -8452,15 +8452,15 @@ // NRF_LOG_ENABLED - nrf_log - Logger //========================================================== #ifndef NRF_LOG_ENABLED -#define NRF_LOG_ENABLED 1 +#define NRF_LOG_ENABLED 0 #endif #ifndef NRF_LOG_BACKEND_RTT_ENABLED -#define NRF_LOG_BACKEND_RTT_ENABLED 1 +#define NRF_LOG_BACKEND_RTT_ENABLED 0 #endif #ifndef NRF_LOG_BACKEND_SERIAL_USES_RTT -#define NRF_LOG_BACKEND_SERIAL_USES_RTT 1 +#define NRF_LOG_BACKEND_SERIAL_USES_RTT 0 #endif // Log message pool - Configuration of log message pool