Convert Spi and GFX to C++.

This commit is contained in:
JF 2019-12-07 17:11:50 +01:00
parent 0db16bd827
commit 6fbb6c8f70
13 changed files with 308 additions and 564 deletions

View file

@ -263,12 +263,6 @@ macro(nRF5x_setup)
) )
list(APPEND SDK_SOURCE_FILES list(APPEND SDK_SOURCE_FILES
"${NRF5_SDK_PATH}/components/libraries/gfx/nrf_gfx.c"
# "${NRF5_SDK_PATH}/integration/nrfx/legacy/nrf_drv_spi.c"
# "${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_spim.c"
# "${NRF5_SDK_PATH}/modules/nrfx/drivers/src/prs/nrfx_prs.c"
# "${NRF5_SDK_PATH}/components/drivers_ext/st7735/st7735.c"
"${NRF5_SDK_PATH}/external/thedotfactory_fonts/orkney24pts.c" "${NRF5_SDK_PATH}/external/thedotfactory_fonts/orkney24pts.c"
) )

View file

@ -33,8 +33,9 @@ list(APPEND SOURCE_FILES
DisplayApp/DisplayApp.cpp DisplayApp/DisplayApp.cpp
DisplayApp/lcdfont.c DisplayApp/lcdfont.c
main.cpp main.cpp
drivers/st7789.cpp drivers/St7789.cpp
drivers/spi_master_fast.cpp drivers/SpiMaster.cpp
Components/Gfx/Gfx.cpp
) )
set(INCLUDE_FILES set(INCLUDE_FILES
@ -43,8 +44,9 @@ set(INCLUDE_FILES
BlinkApp/BlinkApp.h BlinkApp/BlinkApp.h
DisplayApp/DisplayApp.h DisplayApp/DisplayApp.h
DisplayApp/lcdfont.h DisplayApp/lcdfont.h
drivers/st7789.h drivers/St7789.h
drivers/spi_master_fast.h drivers/SpiMaster.h
Components/Gfx/Gfx.h
) )
nRF5x_addExecutable(pinetime-app "${SOURCE_FILES}") nRF5x_addExecutable(pinetime-app "${SOURCE_FILES}")

View file

@ -0,0 +1,76 @@
#include <libraries/svc/nrf_svci.h>
#include "Gfx.h"
#include "../../drivers/St7789.h"
using namespace Pinetime::Components;
Gfx::Gfx(Pinetime::Drivers::St7789 &lcd) : lcd{lcd} {
lcd.Init();
}
void Gfx::ClearScreen() {
lcd.FillRectangle(0, 0, width, height, 0xffff);
}
void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char *text, const FONT_INFO *p_font, bool wrap) {
if (y > (height - p_font->height)) {
// Not enough space to write even single char.
return;
}
uint8_t current_x = x;
uint8_t current_y = y;
for (size_t i = 0; text[i] != '\0'; i++) {
if (text[i] == '\n') {
current_x = x;
current_y += p_font->height + p_font->height / 10;
} else {
DrawChar(p_font, (uint8_t) text[i], &current_x, current_y, color);
}
uint8_t char_idx = text[i] - p_font->startChar;
uint16_t char_width = text[i] == ' ' ? (p_font->height / 2) : p_font->charInfo[char_idx].widthBits;
if (current_x > (width - char_width)) {
if (wrap) {
current_x = x;
current_y += p_font->height + p_font->height / 10;
} else {
break;
}
if (y > (height - p_font->height)) {
break;
}
}
}
}
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);
if (c == ' ') {
*x += font->height / 2;
return;
}
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]) {
pixel_draw(*x + j * 8 + k, y + i, color);
}
}
}
}
*x += font->charInfo[char_idx].widthBits + font->spacePixels;
}
void Gfx::pixel_draw(uint8_t x, uint8_t y, uint16_t color) {
lcd.DrawPixel(x, y, color);
}

26
src/Components/Gfx/Gfx.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
#include <nrf_font.h>
namespace Pinetime {
namespace Drivers {
class St7789;
}
namespace Components {
class Gfx {
public:
explicit Gfx(Drivers::St7789& lcd);
void ClearScreen();
void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO *p_font, bool wrap);
void DrawChar(const FONT_INFO *font, uint8_t c, uint8_t *x, uint8_t y, uint16_t color);
private:
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);
};
}
}

View file

@ -3,57 +3,11 @@
#include <task.h> #include <task.h>
#include <libraries/log/nrf_log.h> #include <libraries/log/nrf_log.h>
#include <boards.h> #include <boards.h>
#include <libraries/gfx/nrf_gfx.h> #include <nrf_font.h>
#include "Components/Gfx/Gfx.h"
using namespace Pinetime::Applications; using namespace Pinetime::Applications;
Pinetime::Drivers::st7789 lcd;
ret_code_t lcd_init() {
return lcd.Init();
}
void lcd_dummy() {
};
void lcd_pixel_draw(uint16_t x, uint16_t y, uint32_t color) {
lcd.DrawPixel(x, y, color);
}
void lcd_rectangle_draw(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color) {
lcd.FillRectangle(x, y, width, height, color);
}
void lcd_rotation_set(nrf_lcd_rotation_t rotation) {
}
void lcd_display_invert(bool invert) {
}
static lcd_cb_t st7789_cb = {
.height = 240,
.width = 240
};
static const nrf_lcd_t nrf_lcd_st7789 = {
.lcd_init = lcd_init,
.lcd_uninit = lcd_dummy,
.lcd_pixel_draw = lcd_pixel_draw,
.lcd_rect_draw = lcd_rectangle_draw,
.lcd_display = lcd_dummy,
.lcd_rotation_set = lcd_rotation_set,
.lcd_display_invert = lcd_display_invert,
.p_lcd_cb = &st7789_cb
};
//extern const FONT_INFO orkney_24ptFontInfo;
//extern const uint_8 lCD_30ptBitmaps[];
extern const FONT_INFO lCD_70ptFontInfo;
//extern const FONT_CHAR_INFO lCD_30ptDescriptors[];
void DisplayApp::Start() { void DisplayApp::Start() {
if (pdPASS != xTaskCreate(DisplayApp::Process, "DisplayApp", 256, this, 0, &taskHandle)) if (pdPASS != xTaskCreate(DisplayApp::Process, "DisplayApp", 256, this, 0, &taskHandle))
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
@ -62,123 +16,49 @@ void DisplayApp::Start() {
void DisplayApp::Process(void *instance) { void DisplayApp::Process(void *instance) {
auto* app = static_cast<DisplayApp*>(instance); auto* app = static_cast<DisplayApp*>(instance);
NRF_LOG_INFO("DisplayApp task started!"); NRF_LOG_INFO("DisplayApp task started!");
app->gfx_initialization(); app->InitHw();
uint8_t hour = 0;
uint8_t minute = 1;
while (1) { while (1) {
NRF_LOG_INFO("BlinkApp task running!"); NRF_LOG_INFO("BlinkApp task running!");
nrf_gfx_rect_t rect;
rect.height = 74;
rect.width = 52;
rect.x = 7;
rect.y = 78;
nrf_gfx_rect_draw(&nrf_lcd_st7789, &rect, 2, 0x00000000, true);
nrf_gfx_font_desc_t font;
font.charInfo = lCD_70ptFontInfo.charInfo;
font.data = lCD_70ptFontInfo.data;
font.endChar = lCD_70ptFontInfo.endChar;
font.height = lCD_70ptFontInfo.height;
font.spacePixels = lCD_70ptFontInfo.spacePixels;
font.startChar = lCD_70ptFontInfo.startChar;
char t[2];
sprintf(t, "%1d", hour);
nrf_gfx_point_t point;
point.x = 7;
point.y = 78;
nrf_gfx_print(&nrf_lcd_st7789,
&point,
0xffff,
t,
&font,
true);
// point.x = 61;
// point.y = 78;
// nrf_gfx_print(&nrf_lcd_st7789,
// &point,
// 0xffff,
// "2",
// &font,
// true);
//
// point.x = 115;
// point.y = 78;
// nrf_gfx_print(&nrf_lcd_st7789,
// &point,
// 0xffff,
// ":",
// &font,
// true);
//
// point.x = 127;
// point.y = 78;
// nrf_gfx_print(&nrf_lcd_st7789,
// &point,
// 0xffff,
// "3",
// &font,
// true);
//
// point.x = 181;
// point.y = 78;
// nrf_gfx_print(&nrf_lcd_st7789,
// &point,
// 0xffff,
// "4",
// &font,
// true);
if(hour < 9)
hour++;
else hour = 0;
vTaskDelay(1000); vTaskDelay(1000);
} }
} }
void DisplayApp::gfx_initialization(void) void DisplayApp::InitHw() {
{
nrf_gpio_cfg_output(14); nrf_gpio_cfg_output(14);
nrf_gpio_cfg_output(22); nrf_gpio_cfg_output(22);
nrf_gpio_cfg_output(23); nrf_gpio_cfg_output(23);
nrf_gpio_pin_clear(14); nrf_gpio_pin_clear(14);
nrf_gpio_pin_set(22); nrf_gpio_pin_clear(22);
nrf_gpio_pin_set(23); nrf_gpio_pin_clear(23);
APP_ERROR_CHECK(nrf_gfx_init(&nrf_lcd_st7789)); Drivers::SpiMaster::Parameters params;
nrf_gfx_rect_t rect; params.bitOrder = Drivers::SpiMaster::BitOrder::Msb_Lsb;
rect.height = 240; params.mode = Drivers::SpiMaster::Modes::Mode3;
rect.width = 240; params.Frequency = Drivers::SpiMaster::Frequencies::Freq8Mhz;
rect.x = 0; params.pinCSN = 25;
rect.y = 0; params.pinMISO = 4;
nrf_gfx_rect_draw(&nrf_lcd_st7789, &rect, 2, 0x00000000, true); params.pinMOSI = 3;
params.pinSCK = 2;
spi.Init(Drivers::SpiMaster::SpiModule::SPI0, params);
nrf_gfx_point_t point; lcd.reset(new Drivers::St7789(spi, 18));
point.x = 7; gfx.reset(new Components::Gfx(*lcd.get()));
point.y = 78; gfx->ClearScreen();
nrf_gfx_font_desc_t font; uint8_t x = 7;
font.charInfo = lCD_70ptFontInfo.charInfo; gfx->DrawChar(&largeFont , '0', &x, 78, 0x0);
font.data = lCD_70ptFontInfo.data;
font.endChar = lCD_70ptFontInfo.endChar;
font.height = lCD_70ptFontInfo.height;
font.spacePixels = lCD_70ptFontInfo.spacePixels;
font.startChar = lCD_70ptFontInfo.startChar;
x = 61;
gfx->DrawChar(&largeFont, '1', &x, 78, 0x0);
nrf_gfx_print(&nrf_lcd_st7789, x = 115;
&point, gfx->DrawChar(&largeFont, ':', &x, 78, 0x0);
0xffff,
"20:45",
&font,
true);
x = 127;
gfx->DrawChar(&largeFont, '2', &x, 78, 0x0);
x = 181;
gfx->DrawChar(&largeFont, '3', &x, 78, 0x0);
} }

View file

@ -1,18 +1,27 @@
#pragma once #pragma once
#include <FreeRTOS.h> #include <FreeRTOS.h>
#include <task.h> #include <task.h>
#include <drivers/st7789.h> #include <drivers/St7789.h>
#include <drivers/SpiMaster.h>
#include <Components/Gfx/Gfx.h>
#include <bits/unique_ptr.h>
extern const FONT_INFO lCD_70ptFontInfo;
namespace Pinetime { namespace Pinetime {
namespace Applications { namespace Applications {
class DisplayApp { class DisplayApp {
public: public:
void Start(); void Start();
private: private:
TaskHandle_t taskHandle; TaskHandle_t taskHandle;
static void Process(void* instance); static void Process(void* instance);
void gfx_initialization(); void InitHw();
Pinetime::Drivers::SpiMaster spi;
std::unique_ptr<Drivers::St7789> lcd;
std::unique_ptr<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};
}; };
} }
} }

88
src/drivers/SpiMaster.cpp Normal file
View file

@ -0,0 +1,88 @@
#include <hal/nrf_gpio.h>
#include "SpiMaster.h"
using namespace Pinetime::Drivers;
bool SpiMaster::Init(const SpiMaster::SpiModule spi, const SpiMaster::Parameters &params) {
/* Configure GPIO pins used for pselsck, pselmosi, pselmiso and pselss for SPI0 */
nrf_gpio_cfg_output(params.pinSCK);
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;
default: return false;
}
/* Configure pins, frequency and mode */
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;
switch(params.Frequency) {
case Frequencies::Freq8Mhz: frequency = 0x80000000; break;
default: return false;
}
spiBaseAddress->FREQUENCY = frequency;
uint32_t regConfig = 0;
switch(params.bitOrder) {
case BitOrder::Msb_Lsb: break;
case BitOrder::Lsb_Msb: regConfig = 1;
default: return false;
}
switch(params.mode) {
case Modes::Mode0: break;
case Modes::Mode1: regConfig |= (0x01 << 1); break;
case Modes::Mode2: regConfig |= (0x02 << 1); break;
case Modes::Mode3: regConfig |= (0x03 << 1); break;
default: return false;
}
spiBaseAddress->CONFIG = regConfig;
spiBaseAddress->EVENTS_READY = 0;
spiBaseAddress->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos);
return true;
}
bool SpiMaster::Write(const uint8_t *data, size_t size) {
volatile uint32_t dummyread;
if(data == nullptr) return false;
/* enable slave (slave select active low) */
nrf_gpio_pin_clear(pinCsn);
spiBaseAddress->EVENTS_READY = 0;
spiBaseAddress->TXD = (uint32_t)*data++;
while(--size)
{
spiBaseAddress->TXD = (uint32_t)*data++;
/* Wait for the transaction complete or timeout (about 10ms - 20 ms) */
while (spiBaseAddress->EVENTS_READY == 0);
/* clear the event to be ready to receive next messages */
spiBaseAddress->EVENTS_READY = 0;
dummyread = spiBaseAddress->RXD;
}
/* Wait for the transaction complete or timeout (about 10ms - 20 ms) */
while (spiBaseAddress->EVENTS_READY == 0);
dummyread = spiBaseAddress->RXD;
/* disable slave (slave select active low) */
nrf_gpio_pin_set(pinCsn);
return true;
}

32
src/drivers/SpiMaster.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <array>
namespace Pinetime {
namespace Drivers {
class SpiMaster {
public:;
enum class SpiModule : uint8_t {SPI0, SPI1};
enum class BitOrder : uint8_t {Msb_Lsb, Lsb_Msb};
enum class Modes : uint8_t {Mode0, Mode1, Mode2, Mode3};
enum class Frequencies : uint8_t {Freq8Mhz};
struct Parameters {
BitOrder bitOrder;
Modes mode;
Frequencies Frequency;
uint8_t pinSCK;
uint8_t pinMOSI;
uint8_t pinMISO;
uint8_t pinCSN;
};
bool Init(const SpiModule spi, const Parameters& params);
bool Write(const uint8_t* data, size_t size);
private:
NRF_SPI_Type * spiBaseAddress;
uint8_t pinCsn;
};
}
}

View file

@ -1,35 +1,17 @@
#include <hal/nrf_gpio.h> #include <hal/nrf_gpio.h>
#include <libraries/delay/nrf_delay.h> #include <libraries/delay/nrf_delay.h>
#include "st7789.h" #include "St7789.h"
#include "spi_master_fast.h" #include "SpiMaster.h"
using namespace Pinetime::Drivers; using namespace Pinetime::Drivers;
ret_code_t st7789::Init() { St7789::St7789(SpiMaster &spiMaster, uint8_t pinDataCommand) : spi{spiMaster}, pinDataCommand{pinDataCommand} {
InitHw();
InitCommands();
return 0;
} }
ret_code_t st7789::InitHw() const {
nrf_gpio_cfg_output(ST7735_DC_PIN);
SPI_config_t spi_config;
spi_config.pin_SCK = ST7735_SCK_PIN; void St7789::Init() {
spi_config.pin_MOSI = ST7735_MOSI_PIN; nrf_gpio_cfg_output(pinDataCommand);
spi_config.pin_MISO = ST7735_MISO_PIN;
spi_config.pin_CSN = ST7735_SS_PIN;
spi_config.frequency = SPI_FREQ_8MBPS;
spi_config.config.fields.mode = SPI_MODE3;
spi_config.config.fields.bit_order = SPI_BITORDER_MSB_LSB;
spi_master_init(SPI0, &spi_config);
return 0;
}
void st7789::InitCommands() {
SoftwareReset(); SoftwareReset();
SleepOut(); SleepOut();
ColMod(); ColMod();
@ -39,47 +21,45 @@ void st7789::InitCommands() {
DisplayInversionOn(); DisplayInversionOn();
NormalModeOn(); NormalModeOn();
DisplayOn(); DisplayOn();
} }
void st7789::WriteCommand(uint8_t cmd) { void St7789::WriteCommand(uint8_t cmd) {
nrf_gpio_pin_clear(ST7735_DC_PIN); nrf_gpio_pin_clear(pinDataCommand);
WriteSpi(&cmd, 1); WriteSpi(&cmd, 1);
} }
void st7789::WriteData(uint8_t data) { void St7789::WriteData(uint8_t data) {
nrf_gpio_pin_set(ST7735_DC_PIN); nrf_gpio_pin_set(pinDataCommand);
WriteSpi(&data, 1); WriteSpi(&data, 1);
} }
void st7789::WriteSpi(const uint8_t* data, size_t size) { void St7789::WriteSpi(const uint8_t* data, size_t size) {
// APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, data, size, nullptr, 0)); spi.Write(data, size);
spi_master_tx(SPI0, size, data);
} }
void st7789::SoftwareReset() { void St7789::SoftwareReset() {
WriteCommand(static_cast<uint8_t>(Commands::SoftwareReset)); WriteCommand(static_cast<uint8_t>(Commands::SoftwareReset));
nrf_delay_ms(150); nrf_delay_ms(150);
} }
void st7789::SleepOut() { void St7789::SleepOut() {
WriteCommand(static_cast<uint8_t>(Commands::SleepOut)); WriteCommand(static_cast<uint8_t>(Commands::SleepOut));
nrf_delay_ms(500); nrf_delay_ms(500);
} }
void st7789::ColMod() { void St7789::ColMod() {
WriteCommand(static_cast<uint8_t>(Commands::ColMod)); WriteCommand(static_cast<uint8_t>(Commands::ColMod));
WriteData(0x55); WriteData(0x55);
nrf_delay_ms(10); nrf_delay_ms(10);
} }
void st7789::MemoryDataAccessControl() { void St7789::MemoryDataAccessControl() {
WriteCommand(static_cast<uint8_t>(Commands::MemoryDataAccessControl)); WriteCommand(static_cast<uint8_t>(Commands::MemoryDataAccessControl));
WriteData(0x00); WriteData(0x00);
} }
void st7789::ColumnAddressSet() { void St7789::ColumnAddressSet() {
WriteCommand(static_cast<uint8_t>(Commands::ColumnAddressSet)); WriteCommand(static_cast<uint8_t>(Commands::ColumnAddressSet));
WriteData(0x00); WriteData(0x00);
WriteData(0x00); WriteData(0x00);
@ -87,7 +67,7 @@ void st7789::ColumnAddressSet() {
WriteData(Height & 0xff); WriteData(Height & 0xff);
} }
void st7789::RowAddressSet() { void St7789::RowAddressSet() {
WriteCommand(static_cast<uint8_t>(Commands::RowAddressSet)); WriteCommand(static_cast<uint8_t>(Commands::RowAddressSet));
WriteData(0x00); WriteData(0x00);
WriteData(0x00); WriteData(0x00);
@ -95,22 +75,22 @@ void st7789::RowAddressSet() {
WriteData(Width & 0xff); WriteData(Width & 0xff);
} }
void st7789::DisplayInversionOn() { void St7789::DisplayInversionOn() {
WriteCommand(static_cast<uint8_t>(Commands::DisplayInversionOn)); WriteCommand(static_cast<uint8_t>(Commands::DisplayInversionOn));
nrf_delay_ms(10); nrf_delay_ms(10);
} }
void st7789::NormalModeOn() { void St7789::NormalModeOn() {
WriteCommand(static_cast<uint8_t>(Commands::NormalModeOn)); WriteCommand(static_cast<uint8_t>(Commands::NormalModeOn));
nrf_delay_ms(10); nrf_delay_ms(10);
} }
void st7789::DisplayOn() { void St7789::DisplayOn() {
WriteCommand(static_cast<uint8_t>(Commands::DisplayOn)); WriteCommand(static_cast<uint8_t>(Commands::DisplayOn));
nrf_delay_ms(500); nrf_delay_ms(500);
} }
void st7789::FillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) { void St7789::FillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) {
// rudimentary clipping (drawChar w/big text requires this) // rudimentary clipping (drawChar w/big text requires this)
if((x >= Width) || (y >= Height)) return; if((x >= Width) || (y >= Height)) return;
if((x + width - 1) >= Width) width = Width - x; if((x + width - 1) >= Width) width = Width - x;
@ -121,7 +101,7 @@ void st7789::FillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t heig
uint8_t hi = color >> 8, lo = color; uint8_t hi = color >> 8, lo = color;
uint32_t c = color + (color << 16); uint32_t c = color + (color << 16);
nrf_gpio_pin_set(ST7735_DC_PIN); nrf_gpio_pin_set(pinDataCommand);
for(y=height+ST7789_ROW_OFFSET; y>ST7789_ROW_OFFSET; y--) { for(y=height+ST7789_ROW_OFFSET; y>ST7789_ROW_OFFSET; y--) {
for(x=width; x>0; x--) { for(x=width; x>0; x--) {
WriteSpi(reinterpret_cast<const uint8_t *>(&c), 4); WriteSpi(reinterpret_cast<const uint8_t *>(&c), 4);
@ -129,7 +109,7 @@ void st7789::FillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t heig
} }
} }
void st7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { void St7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
WriteCommand(static_cast<uint8_t>(Commands::ColumnAddressSet)); WriteCommand(static_cast<uint8_t>(Commands::ColumnAddressSet));
WriteData(x0 >> 8); WriteData(x0 >> 8);
WriteData(x0 & 0xff); WriteData(x0 & 0xff);
@ -145,24 +125,25 @@ void st7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
WriteToRam(); WriteToRam();
} }
void st7789::WriteToRam() { void St7789::WriteToRam() {
WriteCommand(static_cast<uint8_t>(Commands::WriteToRam)); WriteCommand(static_cast<uint8_t>(Commands::WriteToRam));
} }
void st7789::DisplayOff() { void St7789::DisplayOff() {
WriteCommand(static_cast<uint8_t>(Commands::DisplayOff)); WriteCommand(static_cast<uint8_t>(Commands::DisplayOff));
nrf_delay_ms(500); nrf_delay_ms(500);
} }
void st7789::Uninit() { void St7789::Uninit() {
} }
void st7789::DrawPixel(uint16_t x, uint16_t y, uint32_t color) { void St7789::DrawPixel(uint16_t x, uint16_t y, uint32_t color) {
if((x < 0) ||(x >= Width) || (y < 0) || (y >= Height)) return; if((x < 0) ||(x >= Width) || (y < 0) || (y >= Height)) return;
SetAddrWindow(x, y, x+1, y+1); SetAddrWindow(x, y, x+1, y+1);
nrf_gpio_pin_set(ST7735_DC_PIN); nrf_gpio_pin_set(pinDataCommand);
WriteSpi(reinterpret_cast<const uint8_t *>(&color), 2); WriteSpi(reinterpret_cast<const uint8_t *>(&color), 2);
} }

View file

@ -1,18 +1,21 @@
#pragma once #pragma once
#include <cstddef>
namespace Pinetime { namespace Pinetime {
namespace Drivers { namespace Drivers {
class st7789 { class SpiMaster;
class St7789 {
public: public:
ret_code_t Init(); explicit St7789(SpiMaster& spiMaster, uint8_t pinDataCommand);
void Init();
void Uninit(); void Uninit();
void DrawPixel(uint16_t x, uint16_t y, uint32_t color); void DrawPixel(uint16_t x, uint16_t y, uint32_t color);
void DrawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color);
void FillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color); void FillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color);
private: private:
ret_code_t InitHw() const; SpiMaster& spi;
void InitCommands(); uint8_t pinDataCommand;
void SoftwareReset(); void SoftwareReset();
void SleepOut(); void SleepOut();

View file

@ -1,176 +0,0 @@
/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic
* Semiconductor ASA.Terms and conditions of usage are described in detail
* in NORDIC SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
#include "spi_master_fast.h"
#include <string.h>
#include "nrf_gpio.h"
#include "nrf_delay.h"
static SPI_config_t spi_config_table[2];
static NRF_SPI_Type *spi_base[2] = {NRF_SPI0, NRF_SPI1};
static NRF_SPI_Type *SPI;
uint32_t* spi_master_init(SPI_module_number_t spi_num, SPI_config_t *spi_config)
{
if(spi_num > 1)
{
return 0;
}
memcpy(&spi_config_table[spi_num], spi_config, sizeof(SPI_config_t));
/* Configure GPIO pins used for pselsck, pselmosi, pselmiso and pselss for SPI0 */
nrf_gpio_cfg_output(spi_config->pin_SCK);
nrf_gpio_cfg_output(spi_config->pin_MOSI);
nrf_gpio_cfg_input(spi_config->pin_MISO, NRF_GPIO_PIN_NOPULL);
nrf_gpio_cfg_output(spi_config->pin_CSN);
/* Configure pins, frequency and mode */
spi_base[spi_num]->PSELSCK = spi_config->pin_SCK;
spi_base[spi_num]->PSELMOSI = spi_config->pin_MOSI;
spi_base[spi_num]->PSELMISO = spi_config->pin_MISO;
nrf_gpio_pin_set(spi_config->pin_CSN); /* disable Set slave select (inactive high) */
spi_base[spi_num]->FREQUENCY = (uint32_t)spi_config->frequency << 24;
spi_base[spi_num]->CONFIG = spi_config->config.SPI_cfg;
spi_base[spi_num]->EVENTS_READY = 0;
/* Enable */
spi_base[spi_num]->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos);
return (uint32_t *)spi_base[spi_num];
}
bool spi_master_tx_rx(SPI_module_number_t spi_num, uint16_t transfer_size, const uint8_t *tx_data, uint8_t *rx_data)
{
volatile uint32_t *SPI_DATA_READY;
uint32_t tmp;
if(tx_data == 0 || rx_data == 0)
{
return false;
}
SPI = spi_base[spi_num];
SPI_DATA_READY = &SPI->EVENTS_READY;
/* enable slave (slave select active low) */
nrf_gpio_pin_clear(spi_config_table[spi_num].pin_CSN);
*SPI_DATA_READY = 0;
SPI->TXD = (uint32_t)*tx_data++;
tmp = (uint32_t)*tx_data++;
while(--transfer_size)
{
SPI->TXD = tmp;
tmp = (uint32_t)*tx_data++;
/* Wait for the transaction complete or timeout (about 10ms - 20 ms) */
while (*SPI_DATA_READY == 0);
/* clear the event to be ready to receive next messages */
*SPI_DATA_READY = 0;
*rx_data++ = SPI->RXD;
}
/* Wait for the transaction complete or timeout (about 10ms - 20 ms) */
while (*SPI_DATA_READY == 0);
*rx_data = SPI->RXD;
/* disable slave (slave select active low) */
nrf_gpio_pin_set(spi_config_table[spi_num].pin_CSN);
return true;
}
bool spi_master_tx(SPI_module_number_t spi_num, uint16_t transfer_size, const uint8_t *tx_data)
{
volatile uint32_t dummyread;
if(tx_data == 0)
{
return false;
}
SPI = spi_base[spi_num];
/* enable slave (slave select active low) */
nrf_gpio_pin_clear(spi_config_table[spi_num].pin_CSN);
SPI->EVENTS_READY = 0;
SPI->TXD = (uint32_t)*tx_data++;
while(--transfer_size)
{
SPI->TXD = (uint32_t)*tx_data++;
/* Wait for the transaction complete or timeout (about 10ms - 20 ms) */
while (SPI->EVENTS_READY == 0);
/* clear the event to be ready to receive next messages */
SPI->EVENTS_READY = 0;
dummyread = SPI->RXD;
}
/* Wait for the transaction complete or timeout (about 10ms - 20 ms) */
while (SPI->EVENTS_READY == 0);
dummyread = SPI->RXD;
/* disable slave (slave select active low) */
nrf_gpio_pin_set(spi_config_table[spi_num].pin_CSN);
return true;
}
bool spi_master_rx(SPI_module_number_t spi_num, uint16_t transfer_size, uint8_t *rx_data)
{
if(rx_data == 0)
{
return false;
}
SPI = spi_base[spi_num];
/* enable slave (slave select active low) */
nrf_gpio_pin_clear(spi_config_table[spi_num].pin_CSN);
SPI->EVENTS_READY = 0;
SPI->TXD = 0;
while(--transfer_size)
{
SPI->TXD = 0;
/* Wait for the transaction complete or timeout (about 10ms - 20 ms) */
while (SPI->EVENTS_READY == 0);
/* clear the event to be ready to receive next messages */
SPI->EVENTS_READY = 0;
*rx_data++ = SPI->RXD;
}
/* Wait for the transaction complete or timeout (about 10ms - 20 ms) */
while (SPI->EVENTS_READY == 0);
*rx_data = SPI->RXD;
/* disable slave (slave select active low) */
nrf_gpio_pin_set(spi_config_table[spi_num].pin_CSN);
return true;
}

View file

@ -1,147 +0,0 @@
/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is confidential property of Nordic
* Semiconductor ASA.Terms and conditions of usage are described in detail
* in NORDIC SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
#ifndef __SPI_MASTER_FAST_H
#define __SPI_MASTER_FAST_H
#include <stdbool.h>
#include <stdint.h>
#define SPI_FAST_DEFAULT_CONFIG {.pin_SCK = 1, .pin_MOSI = 2, .pin_MISO = 3, .pin_CSN = 4, \
.frequency = SPI_FREQ_1MBPS, .config.fields.mode = 0, .config.fields.bit_order = SPI_BITORDER_MSB_LSB}
/**
* SPI master operating frequency
*/
typedef enum
{
SPI_FREQ_125KBPS = 0x02, /*!< drive SClk with frequency 125Kbps */
SPI_FREQ_250KBPS = 0x04, /*!< drive SClk with frequency 250Kbps */
SPI_FREQ_500KBPS = 0x08, /*!< drive SClk with frequency 500Kbps */
SPI_FREQ_1MBPS = 0x10, /*!< drive SClk with frequency 1Mbps */
SPI_FREQ_2MBPS = 0x20, /*!< drive SClk with frequency 2Mbps */
SPI_FREQ_4MBPS = 0x40, /*!< drive SClk with frequency 4Mbps */
SPI_FREQ_8MBPS = 0x80 /*!< drive SClk with frequency 8Mbps */
} SPI_frequency_t;
/**
* SPI master module number
*/
typedef enum
{
SPI0 = 0, /*!< SPI module 0 */
SPI1 /*!< SPI module 1 */
} SPI_module_number_t;
/**
* SPI mode
*/
typedef enum
{
//------------------------Clock polarity 0, Clock starts with level 0-------------------------------------------
SPI_MODE0 = 0, /*!< Sample data at rising edge of clock and shift serial data at falling edge */
SPI_MODE1, /*!< sample data at falling edge of clock and shift serial data at rising edge */
//------------------------Clock polarity 1, Clock starts with level 1-------------------------------------------
SPI_MODE2, /*!< sample data at falling edge of clock and shift serial data at rising edge */
SPI_MODE3 /*!< Sample data at rising edge of clock and shift serial data at falling edge */
} SPI_mode_t;
/**
* SPI master bit ordering
*/
typedef enum
{
SPI_BITORDER_MSB_LSB = 0, /*!< Most significant to least significant bit */
SPI_BITORDER_LSB_MSB /*!< Least significant to most significant bit */
} SPI_bit_order_t;
/**
* Struct containing all parameters necessary to configure the SPI interface
*/
typedef struct
{
union
{
uint8_t SPI_cfg; /*!< Bit mode and bit order merged, as in the SPI CONFIG register */
struct
{
uint8_t bit_order : 1; /*!< SPI master bit order */
uint8_t mode : 2; /*!< SPI master mode */
uint8_t : 5; /*!< Padding */
}fields;
}config;
uint8_t frequency; /*!< SPI master frequency */
uint8_t pin_SCK; /*!< SPI master SCK pin */
uint8_t pin_MOSI; /*!< SPI master MOSI pin */
uint8_t pin_MISO; /*!< SPI master MISO pin */
uint8_t pin_CSN; /*!< SPI master chip select pin */
} SPI_config_t;
/**
* Initializes given SPI master with given configuration.
*
* After initializing the given SPI master with given configuration, this function also test if the
* SPI slave is responding with the configurations by transmitting few test bytes. If the slave did not
* respond then error is returned and contents of the rx_data are invalid.
*
* @param module_number SPI master number (SPIModuleNumber) to initialize.
* @param pointer to a struct of type @ref SPIConfig_t containing the SPI configuration parameters.
* @return
* @retval pointer to direct physical address of the requested SPI module if init was successful
* @retval 0, if either init failed or slave did not respond to the test transfer
*/
uint32_t* spi_master_init(SPI_module_number_t spi_num, SPI_config_t *spi_config);
/**
* Transmit/receive data over SPI bus.
*
* @note Make sure at least transfer_size number of bytes is allocated in tx_data/rx_data.
*
* @param spi_num SPI master number (SPIModuleNumber)
* @param transfer_size number of bytes to transmit/receive over SPI master
* @param tx_data pointer to the data that needs to be transmitted
* @param rx_data pointer to the data that needs to be received
* @return
* @retval true if transmit/reveive of transfer_size were completed.
* @retval false if transmit/reveive of transfer_size were not complete and tx_data/rx_data points to invalid data.
*/
bool spi_master_tx_rx(SPI_module_number_t spi_num, uint16_t transfer_size, const uint8_t *tx_data, uint8_t *rx_data);
/**
* Transmit data over SPI bus.
*
* @note Make sure at least transfer_size number of bytes is allocated in tx_data.
*
* @param spi_num SPI master number (SPIModuleNumber)
* @param transfer_size number of bytes to transmit/receive over SPI master
* @param tx_data pointer to the data that needs to be transmitted
* @return
* @retval true if transmit/reveive of transfer_size were completed.
* @retval false if transmit/reveive of transfer_size were not complete and tx_data/rx_data points to invalid data.
*/
bool spi_master_tx(SPI_module_number_t spi_num, uint16_t transfer_size, const uint8_t *tx_data);
/**
* Receive data over SPI bus.
*
* @note Make sure at least transfer_size number of bytes is allocated in rx_data.
*
* @param spi_num SPI master number (SPIModuleNumber)
* @param transfer_size number of bytes to transmit/receive over SPI master
* @param rx_data pointer to the data that needs to be received
* @return
* @retval true if transmit/reveive of transfer_size were completed.
* @retval false if transmit/reveive of transfer_size were not complete and tx_data/rx_data points to invalid data.
*/
bool spi_master_rx(SPI_module_number_t spi_num, uint16_t transfer_size, uint8_t *rx_data);
#endif

View file

@ -2,16 +2,11 @@
#include <task.h> #include <task.h>
#include <libraries/log/nrf_log.h> #include <libraries/log/nrf_log.h>
#include <BlinkApp/BlinkApp.h> #include <BlinkApp/BlinkApp.h>
#include <boards.h>
#include <libraries/bsp/bsp.h> #include <libraries/bsp/bsp.h>
#include <legacy/nrf_drv_clock.h> #include <legacy/nrf_drv_clock.h>
#include <libraries/timer/app_timer.h> #include <libraries/timer/app_timer.h>
#include <libraries/gpiote/app_gpiote.h> #include <libraries/gpiote/app_gpiote.h>
#include <libraries/gfx/nrf_lcd.h>
#include <drivers/st7789.h>
#include <DisplayApp/DisplayApp.h> #include <DisplayApp/DisplayApp.h>
#include "nrf_gfx.h"
#if NRF_LOG_ENABLED #if NRF_LOG_ENABLED
#include "Logging/NrfLogger.h" #include "Logging/NrfLogger.h"
@ -24,7 +19,6 @@ Pinetime::Logging::DummyLogger logger;
Pinetime::Applications::BlinkApp blinkApp; Pinetime::Applications::BlinkApp blinkApp;
Pinetime::Applications::DisplayApp displayApp; Pinetime::Applications::DisplayApp displayApp;
TaskHandle_t systemThread; TaskHandle_t systemThread;
//Pinetime::Drivers::st7789 lcd;
extern "C" { extern "C" {
void vApplicationIdleHook() { void vApplicationIdleHook() {
@ -48,26 +42,10 @@ static void bsp_event_handler(bsp_event_t event)
} }
} }
void SystemTask(void *) { void SystemTask(void *) {
APP_GPIOTE_INIT(2); APP_GPIOTE_INIT(2);
app_timer_init(); app_timer_init();
nrf_gpio_cfg_output(14);
nrf_gpio_cfg_output(22);
nrf_gpio_cfg_output(23);
nrf_gpio_pin_clear(14);
nrf_gpio_pin_clear(22);
nrf_gpio_pin_clear(23);
// lcd.Init();
// lcd.FillRectangle(0,0,240,240,0xffaa);
// lcd.FillRectangle(10,10,50,50,0x011bb);
//
// lcd.FillRectangle(120,120,120,120,0x1212);
blinkApp.Start(); blinkApp.Start();
displayApp.Start(); displayApp.Start();
@ -76,8 +54,6 @@ void SystemTask(void *) {
} }
} }
int main(void) { int main(void) {
logger.Init(); logger.Init();
nrf_drv_clock_init(); nrf_drv_clock_init();