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

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 <libraries/delay/nrf_delay.h>
#include "st7789.h"
#include "spi_master_fast.h"
#include "St7789.h"
#include "SpiMaster.h"
using namespace Pinetime::Drivers;
ret_code_t st7789::Init() {
InitHw();
InitCommands();
return 0;
St7789::St7789(SpiMaster &spiMaster, uint8_t pinDataCommand) : spi{spiMaster}, pinDataCommand{pinDataCommand} {
}
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() {
void St7789::Init() {
nrf_gpio_cfg_output(pinDataCommand);
SoftwareReset();
SleepOut();
ColMod();
@@ -39,47 +21,45 @@ void st7789::InitCommands() {
DisplayInversionOn();
NormalModeOn();
DisplayOn();
}
void st7789::WriteCommand(uint8_t cmd) {
nrf_gpio_pin_clear(ST7735_DC_PIN);
void St7789::WriteCommand(uint8_t cmd) {
nrf_gpio_pin_clear(pinDataCommand);
WriteSpi(&cmd, 1);
}
void st7789::WriteData(uint8_t data) {
nrf_gpio_pin_set(ST7735_DC_PIN);
void St7789::WriteData(uint8_t data) {
nrf_gpio_pin_set(pinDataCommand);
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::WriteSpi(const uint8_t* data, size_t size) {
spi.Write(data, size);
}
void st7789::SoftwareReset() {
void St7789::SoftwareReset() {
WriteCommand(static_cast<uint8_t>(Commands::SoftwareReset));
nrf_delay_ms(150);
}
void st7789::SleepOut() {
void St7789::SleepOut() {
WriteCommand(static_cast<uint8_t>(Commands::SleepOut));
nrf_delay_ms(500);
}
void st7789::ColMod() {
void St7789::ColMod() {
WriteCommand(static_cast<uint8_t>(Commands::ColMod));
WriteData(0x55);
nrf_delay_ms(10);
}
void st7789::MemoryDataAccessControl() {
void St7789::MemoryDataAccessControl() {
WriteCommand(static_cast<uint8_t>(Commands::MemoryDataAccessControl));
WriteData(0x00);
}
void st7789::ColumnAddressSet() {
void St7789::ColumnAddressSet() {
WriteCommand(static_cast<uint8_t>(Commands::ColumnAddressSet));
WriteData(0x00);
WriteData(0x00);
@@ -87,7 +67,7 @@ void st7789::ColumnAddressSet() {
WriteData(Height & 0xff);
}
void st7789::RowAddressSet() {
void St7789::RowAddressSet() {
WriteCommand(static_cast<uint8_t>(Commands::RowAddressSet));
WriteData(0x00);
WriteData(0x00);
@@ -95,22 +75,22 @@ void st7789::RowAddressSet() {
WriteData(Width & 0xff);
}
void st7789::DisplayInversionOn() {
void St7789::DisplayInversionOn() {
WriteCommand(static_cast<uint8_t>(Commands::DisplayInversionOn));
nrf_delay_ms(10);
}
void st7789::NormalModeOn() {
void St7789::NormalModeOn() {
WriteCommand(static_cast<uint8_t>(Commands::NormalModeOn));
nrf_delay_ms(10);
}
void st7789::DisplayOn() {
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) {
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;
@@ -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;
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(x=width; x>0; x--) {
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));
WriteData(x0 >> 8);
WriteData(x0 & 0xff);
@@ -145,24 +125,25 @@ void st7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
WriteToRam();
}
void st7789::WriteToRam() {
void St7789::WriteToRam() {
WriteCommand(static_cast<uint8_t>(Commands::WriteToRam));
}
void st7789::DisplayOff() {
void St7789::DisplayOff() {
WriteCommand(static_cast<uint8_t>(Commands::DisplayOff));
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;
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);
}

View File

@@ -1,18 +1,21 @@
#pragma once
#include <cstddef>
namespace Pinetime {
namespace Drivers {
class st7789 {
class SpiMaster;
class St7789 {
public:
ret_code_t Init();
explicit St7789(SpiMaster& spiMaster, uint8_t pinDataCommand);
void 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();
SpiMaster& spi;
uint8_t pinDataCommand;
void SoftwareReset();
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