summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/spi_master_fast.cpp176
-rw-r--r--src/drivers/spi_master_fast.h147
-rw-r--r--src/drivers/st7789.cpp171
-rw-r--r--src/drivers/st7789.h58
4 files changed, 540 insertions, 12 deletions
diff --git a/src/drivers/spi_master_fast.cpp b/src/drivers/spi_master_fast.cpp
new file mode 100644
index 0000000..7ef2b36
--- /dev/null
+++ b/src/drivers/spi_master_fast.cpp
@@ -0,0 +1,176 @@
+ /* 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;
+}
diff --git a/src/drivers/spi_master_fast.h b/src/drivers/spi_master_fast.h
new file mode 100644
index 0000000..5cd4d7a
--- /dev/null
+++ b/src/drivers/spi_master_fast.h
@@ -0,0 +1,147 @@
+ /* 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
diff --git a/src/drivers/st7789.cpp b/src/drivers/st7789.cpp
index 6e2fb68..a4d0626 100644
--- a/src/drivers/st7789.cpp
+++ b/src/drivers/st7789.cpp
@@ -1,5 +1,168 @@
-//
-// Created by jf on 12/2/19.
-//
-
+#include <hal/nrf_gpio.h>
+#include <libraries/delay/nrf_delay.h>
#include "st7789.h"
+#include "spi_master_fast.h"
+
+using namespace Pinetime::Drivers;
+
+ret_code_t st7789::Init() {
+ InitHw();
+ InitCommands();
+
+}
+
+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;
+ spi_config.pin_MOSI = ST7735_MOSI_PIN;
+ 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();
+ SleepOut();
+ ColMod();
+ MemoryDataAccessControl();
+ ColumnAddressSet();
+ RowAddressSet();
+ DisplayInversionOn();
+ NormalModeOn();
+ DisplayOn();
+
+}
+
+void st7789::WriteCommand(uint8_t cmd) {
+ nrf_gpio_pin_clear(ST7735_DC_PIN);
+ WriteSpi(&cmd, 1);
+}
+
+void st7789::WriteData(uint8_t data) {
+ nrf_gpio_pin_set(ST7735_DC_PIN);
+ WriteSpi(&data, 1);
+}
+
+
+void st7789::WriteSpi(const uint8_t* data, size_t size) {
+// APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, data, size, nullptr, 0));
+ spi_master_tx(SPI0, size, data);
+}
+
+void st7789::SoftwareReset() {
+ WriteCommand(static_cast<uint8_t>(Commands::SoftwareReset));
+ nrf_delay_ms(150);
+}
+
+void st7789::SleepOut() {
+ WriteCommand(static_cast<uint8_t>(Commands::SleepOut));
+ nrf_delay_ms(500);
+}
+
+void st7789::ColMod() {
+ WriteCommand(static_cast<uint8_t>(Commands::ColMod));
+ WriteData(0x55);
+ nrf_delay_ms(10);
+}
+
+void st7789::MemoryDataAccessControl() {
+ WriteCommand(static_cast<uint8_t>(Commands::MemoryDataAccessControl));
+ WriteData(0x00);
+}
+
+void st7789::ColumnAddressSet() {
+ WriteCommand(static_cast<uint8_t>(Commands::ColumnAddressSet));
+ WriteData(0x00);
+ WriteData(0x00);
+ WriteData(Height >> 8);
+ WriteData(Height & 0xff);
+}
+
+void st7789::RowAddressSet() {
+ WriteCommand(static_cast<uint8_t>(Commands::RowAddressSet));
+ WriteData(0x00);
+ WriteData(0x00);
+ WriteData(Width >> 8);
+ WriteData(Width & 0xff);
+}
+
+void st7789::DisplayInversionOn() {
+ WriteCommand(static_cast<uint8_t>(Commands::DisplayInversionOn));
+ nrf_delay_ms(10);
+}
+
+void st7789::NormalModeOn() {
+ WriteCommand(static_cast<uint8_t>(Commands::NormalModeOn));
+ nrf_delay_ms(10);
+}
+
+void st7789::DisplayOn() {
+ WriteCommand(static_cast<uint8_t>(Commands::DisplayOn));
+ nrf_delay_ms(500);
+}
+
+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)
+ if((x >= Width) || (y >= Height)) return;
+ if((x + width - 1) >= Width) width = Width - x;
+ if((y + height - 1) >= Height) height = Height - y;
+
+ SetAddrWindow(0+x, ST7789_ROW_OFFSET+y, x+width-1, y+height-1);
+
+ uint8_t hi = color >> 8, lo = color;
+ uint32_t c = color + (color << 16);
+
+ nrf_gpio_pin_set(ST7735_DC_PIN);
+ for(y=height+ST7789_ROW_OFFSET; y>ST7789_ROW_OFFSET; y--) {
+ for(x=width; x>0; x--) {
+ WriteSpi(reinterpret_cast<const uint8_t *>(&c), 4);
+ }
+ }
+}
+
+void st7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
+ WriteCommand(static_cast<uint8_t>(Commands::ColumnAddressSet));
+ WriteData(x0 >> 8);
+ WriteData(x0 & 0xff);
+ WriteData(x1 >> 8);
+ WriteData(x1 & 0xff);
+
+ WriteCommand(static_cast<uint8_t>(Commands::RowAddressSet));
+ WriteData(y0>>8);
+ WriteData(y0 & 0xff);
+ WriteData(y1 >> 8);
+ WriteData(y1 & 0xff);
+
+ WriteToRam();
+}
+
+void st7789::WriteToRam() {
+ WriteCommand(static_cast<uint8_t>(Commands::WriteToRam));
+}
+
+void st7789::DisplayOff() {
+ WriteCommand(static_cast<uint8_t>(Commands::DisplayOff));
+ nrf_delay_ms(500);
+}
+
+void st7789::Uninit() {
+
+}
+
+void st7789::DrawPixel(uint16_t x, uint16_t y, uint32_t color) {
+ if((x < 0) ||(x >= Width) || (y < 0) || (y >= Height)) return;
+
+ SetAddrWindow(x, y, x+1, y+1);
+
+ nrf_gpio_pin_set(ST7735_DC_PIN);
+ WriteSpi(reinterpret_cast<const uint8_t *>(&color), 2);
+}
diff --git a/src/drivers/st7789.h b/src/drivers/st7789.h
index dc3f083..6f744a1 100644
--- a/src/drivers/st7789.h
+++ b/src/drivers/st7789.h
@@ -1,14 +1,56 @@
-//
-// Created by jf on 12/2/19.
-//
+#pragma once
-#ifndef PINETIME_ST7789_H
-#define PINETIME_ST7789_H
+namespace Pinetime {
+ namespace Drivers {
+ class st7789 {
+ public:
+ ret_code_t Init();
+ void Uninit();
+ 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);
+ private:
+ ret_code_t InitHw() const;
+ void InitCommands();
-class st7789 {
+ void SoftwareReset();
+ void SleepOut();
+ void ColMod();
+ void MemoryDataAccessControl();
+ void DisplayInversionOn();
+ void NormalModeOn();
+ void WriteToRam();
+ void DisplayOn();
+ void DisplayOff();
-};
+ 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);
+
+ enum class Commands : uint8_t {
+ SoftwareReset = 0x01,
+ SleepOut = 0x11,
+ NormalModeOn = 0x13,
+ DisplayInversionOn = 0x21,
+ DisplayOff = 0x28,
+ DisplayOn = 0x29,
+ ColumnAddressSet = 0x2a,
+ RowAddressSet = 0x2b,
+ WriteToRam = 0x2c,
+ MemoryDataAccessControl = 036,
+ ColMod = 0x3a,
+ };
+ void WriteData(uint8_t data);
+ void ColumnAddressSet();
+
+ static constexpr uint16_t Width = 240;
+ static constexpr uint16_t Height = 240;
+ void RowAddressSet();
+
+ };
+ }
+}
-#endif //PINETIME_ST7789_H