mirror of
https://github.com/InfiniTimeOrg/InfiniTime.git
synced 2026-05-05 12:16:35 +02:00
This commit improves the hardware abstraction by integrating the Concepts features of C++20 for Spi, SpiMaster and SpiNorFlash.
The 'interface' of the drivers are defined in `Pinetime::Drivers::Interface::Spi`, `Pinetime::Drivers::Interface::SpiMaster` and `Pinetime::Drivers::Interface::SpiNorFlash`. The actual implementation will be injected via the template parameter `T`. T is required to conform to the corresponding concepts `IsSpi`, `IsSpiMaster` and `IsFlashMemory`. This implementation should be practically free in terms of memory and cpu resource usage, but it provides way to implement multiple variations of the same driver. It also describes very clearly the interface of the drivers thanks to the concepts. This will allow us to support more easily other hardwares : different SoC, different sensors and memory chips. It'll also make the implemenation of InfiniSim much easier.
This commit is contained in:
parent
b56c5f25f0
commit
2e1227fab2
@ -5,7 +5,7 @@ set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose Debug or Release")
|
||||
project(pinetime VERSION 1.11.0 LANGUAGES C CXX ASM)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# set(CMAKE_GENERATOR "Unix Makefiles")
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
@ -436,9 +436,9 @@ list(APPEND SOURCE_FILES
|
||||
|
||||
main.cpp
|
||||
drivers/St7789.cpp
|
||||
drivers/SpiNorFlash.cpp
|
||||
drivers/SpiMaster.cpp
|
||||
drivers/Spi.cpp
|
||||
drivers/nrf52/SpiMaster.cpp
|
||||
drivers/nrf52/Spi.cpp
|
||||
drivers/spiFlash/SpiNorFlash.cpp
|
||||
drivers/Watchdog.cpp
|
||||
drivers/DebugPins.cpp
|
||||
drivers/InternalFlash.cpp
|
||||
@ -503,9 +503,8 @@ list(APPEND RECOVERY_SOURCE_FILES
|
||||
|
||||
main.cpp
|
||||
drivers/St7789.cpp
|
||||
drivers/SpiNorFlash.cpp
|
||||
drivers/SpiMaster.cpp
|
||||
drivers/Spi.cpp
|
||||
drivers/nrf52/SpiMaster.cpp
|
||||
drivers/nrf52/Spi.cpp
|
||||
drivers/Watchdog.cpp
|
||||
drivers/DebugPins.cpp
|
||||
drivers/InternalFlash.cpp
|
||||
@ -566,9 +565,8 @@ list(APPEND RECOVERYLOADER_SOURCE_FILES
|
||||
FreeRTOS/port_cmsis_systick.c
|
||||
FreeRTOS/port_cmsis.c
|
||||
|
||||
drivers/SpiNorFlash.cpp
|
||||
drivers/SpiMaster.cpp
|
||||
drivers/Spi.cpp
|
||||
drivers/nrf52/SpiMaster.cpp
|
||||
drivers/nrf52/Spi.cpp
|
||||
logging/NrfLogger.cpp
|
||||
|
||||
components/rle/RleDecoder.cpp
|
||||
@ -587,6 +585,7 @@ set(INCLUDE_FILES
|
||||
BootloaderVersion.h
|
||||
logging/Logger.h
|
||||
logging/NrfLogger.h
|
||||
port/infinitime.h
|
||||
displayapp/DisplayApp.h
|
||||
displayapp/Messages.h
|
||||
displayapp/TouchEvents.h
|
||||
@ -619,8 +618,9 @@ set(INCLUDE_FILES
|
||||
displayapp/widgets/StatusIcons.h
|
||||
drivers/St7789.h
|
||||
drivers/SpiNorFlash.h
|
||||
drivers/SpiMaster.h
|
||||
drivers/Spi.h
|
||||
drivers/nrf52/SpiMaster.h
|
||||
drivers/nrf52/Spi.h
|
||||
drivers/spiFlash/SpiNorFlash.h
|
||||
drivers/Watchdog.h
|
||||
drivers/DebugPins.h
|
||||
drivers/InternalFlash.h
|
||||
@ -687,6 +687,7 @@ include_directories(
|
||||
.
|
||||
../
|
||||
libs/
|
||||
port/
|
||||
FreeRTOS/
|
||||
libs/date/include
|
||||
libs/mynewt-nimble/porting/npl/freertos/include
|
||||
|
||||
@ -9,13 +9,13 @@
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
#include <drivers/SpiNorFlash.h>
|
||||
#include "infinitime.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Drivers {
|
||||
class SpiNorFlash;
|
||||
}
|
||||
namespace Controllers {
|
||||
class Ble;
|
||||
|
||||
|
||||
@ -25,10 +25,6 @@
|
||||
#include "components/fs/FS.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
class SpiNorFlash;
|
||||
}
|
||||
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include "drivers/SpiNorFlash.h"
|
||||
#include "port/infinitime.h"
|
||||
#include <littlefs/lfs.h>
|
||||
|
||||
namespace Pinetime {
|
||||
|
||||
@ -1,28 +1,56 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "drivers/SpiMaster.h"
|
||||
#include <utility>
|
||||
#include <concepts>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
class Spi {
|
||||
public:
|
||||
Spi(SpiMaster& spiMaster, uint8_t pinCsn);
|
||||
Spi(const Spi&) = delete;
|
||||
Spi& operator=(const Spi&) = delete;
|
||||
Spi(Spi&&) = delete;
|
||||
Spi& operator=(Spi&&) = delete;
|
||||
template <typename T>
|
||||
concept IsSpi = requires(T s, const uint8_t* constData, uint8_t* data, const uint8_t* constCommand, uint8_t* command, size_t size) {
|
||||
{ s.Write(constData, size) } -> std::same_as<bool>;
|
||||
{ s.Read(command, size, data, size) } -> std::same_as<bool>;
|
||||
};
|
||||
|
||||
bool Init();
|
||||
bool Write(const uint8_t* data, size_t size);
|
||||
bool Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize);
|
||||
bool WriteCmdAndBuffer(const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize);
|
||||
void Sleep();
|
||||
void Wakeup();
|
||||
namespace Interface {
|
||||
template <class T>
|
||||
requires IsSpi<T>
|
||||
class Spi {
|
||||
public:
|
||||
Spi(T& spi) : impl {spi} {
|
||||
}
|
||||
Spi(const Spi&) = delete;
|
||||
Spi& operator=(const Spi&) = delete;
|
||||
Spi(Spi&&) = delete;
|
||||
Spi& operator=(Spi&&) = delete;
|
||||
|
||||
private:
|
||||
SpiMaster& spiMaster;
|
||||
uint8_t pinCsn;
|
||||
};
|
||||
bool Init() {
|
||||
return impl.Init();
|
||||
}
|
||||
|
||||
bool Write(const uint8_t* data, size_t size) {
|
||||
return impl.Write(data, size);
|
||||
}
|
||||
|
||||
bool Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize) {
|
||||
return impl.Read(cmd, cmdSize, data, dataSize);
|
||||
}
|
||||
|
||||
bool WriteCmdAndBuffer(const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize) {
|
||||
return impl.WriteCmdAndBuffer(cmd, cmdSize, data, dataSize);
|
||||
}
|
||||
|
||||
void Sleep() {
|
||||
impl.Sleep();
|
||||
}
|
||||
|
||||
void Wakeup() {
|
||||
impl.Wakeup();
|
||||
}
|
||||
|
||||
private:
|
||||
T& impl;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,65 +1,70 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
#include <task.h>
|
||||
#include <algorithm>
|
||||
|
||||
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;
|
||||
template <typename T>
|
||||
concept IsSpiMaster =
|
||||
requires(T spi, uint8_t pin, const uint8_t* constData, uint8_t* data, const uint8_t* constCommand, uint8_t* command, size_t size) {
|
||||
{ spi.Init() } -> std::same_as<bool>;
|
||||
{ spi.Write(pin, constData, size) } -> std::same_as<bool>;
|
||||
{ spi.Read(pin, command, size, data, size) } -> std::same_as<bool>;
|
||||
{ spi.WriteCmdAndBuffer(pin, constCommand, size, constData, size) } -> std::same_as<bool>;
|
||||
{ spi.OnStartedEvent() };
|
||||
{ spi.OnEndEvent() };
|
||||
{ spi.Sleep() };
|
||||
{ spi.Wakeup() };
|
||||
};
|
||||
|
||||
SpiMaster(const SpiModule spi, const Parameters& params);
|
||||
SpiMaster(const SpiMaster&) = delete;
|
||||
SpiMaster& operator=(const SpiMaster&) = delete;
|
||||
SpiMaster(SpiMaster&&) = delete;
|
||||
SpiMaster& operator=(SpiMaster&&) = delete;
|
||||
namespace Interface {
|
||||
template <class T>
|
||||
requires IsSpiMaster<T>
|
||||
class SpiMaster {
|
||||
public:
|
||||
SpiMaster(T& spiMaster) : impl {spiMaster} {
|
||||
}
|
||||
SpiMaster(const SpiMaster&) = delete;
|
||||
SpiMaster& operator=(const SpiMaster&) = delete;
|
||||
SpiMaster(SpiMaster&&) = delete;
|
||||
SpiMaster& operator=(SpiMaster&&) = delete;
|
||||
|
||||
bool Init();
|
||||
bool Write(uint8_t pinCsn, const uint8_t* data, size_t size);
|
||||
bool Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize);
|
||||
bool Init() {
|
||||
return impl.Init();
|
||||
}
|
||||
|
||||
bool WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize);
|
||||
bool Write(uint8_t pinCsn, const uint8_t* data, size_t size) {
|
||||
return impl.Write(pinCsn, data, size);
|
||||
}
|
||||
|
||||
void OnStartedEvent();
|
||||
void OnEndEvent();
|
||||
bool Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize) {
|
||||
return impl.Read(pinCsn, cmd, cmdSize, data, dataSize);
|
||||
}
|
||||
|
||||
void Sleep();
|
||||
void Wakeup();
|
||||
bool WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize) {
|
||||
return impl.WriteCmdAndBuffer(pinCsn, cmd, cmdSize, data, dataSize);
|
||||
}
|
||||
|
||||
private:
|
||||
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);
|
||||
void PrepareRx(const volatile uint32_t cmdAddress,
|
||||
const volatile size_t cmdSize,
|
||||
const volatile uint32_t bufferAddress,
|
||||
const volatile size_t size);
|
||||
void OnStartedEvent() {
|
||||
impl.OnStartedEvent();
|
||||
}
|
||||
|
||||
NRF_SPIM_Type* spiBaseAddress;
|
||||
uint8_t pinCsn;
|
||||
void OnEndEvent() {
|
||||
impl.OnEndEvent();
|
||||
}
|
||||
|
||||
SpiMaster::SpiModule spi;
|
||||
SpiMaster::Parameters params;
|
||||
void Sleep() {
|
||||
impl.Sleep();
|
||||
}
|
||||
|
||||
volatile uint32_t currentBufferAddr = 0;
|
||||
volatile size_t currentBufferSize = 0;
|
||||
volatile TaskHandle_t taskToNotify;
|
||||
SemaphoreHandle_t mutex = nullptr;
|
||||
};
|
||||
void Wakeup() {
|
||||
impl.Wakeup();
|
||||
}
|
||||
|
||||
private:
|
||||
T& impl;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,60 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <concepts>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
class Spi;
|
||||
class SpiNorFlash {
|
||||
public:
|
||||
explicit SpiNorFlash(Spi& spi);
|
||||
SpiNorFlash(const SpiNorFlash&) = delete;
|
||||
SpiNorFlash& operator=(const SpiNorFlash&) = delete;
|
||||
SpiNorFlash(SpiNorFlash&&) = delete;
|
||||
SpiNorFlash& operator=(SpiNorFlash&&) = delete;
|
||||
template <typename T>
|
||||
concept IsFlashMemory = requires(T memory, uint32_t address, uint8_t* buffer, const uint8_t* constBuffer, size_t size) {
|
||||
{ memory.ReadIdentification() };
|
||||
{ memory.ReadStatusRegister() } -> std::same_as<uint8_t>;
|
||||
{ memory.ReadConfigurationRegister() } -> std::same_as<uint8_t>;
|
||||
{ memory.WriteInProgress() } -> std::same_as<bool>;
|
||||
{ memory.WriteEnabled() } -> std::same_as<bool>;
|
||||
{ memory.Read(address, buffer, size) };
|
||||
{ memory.Write(address, constBuffer, size) };
|
||||
{ memory.WriteEnable() };
|
||||
{ memory.SectorErase(address) };
|
||||
{ memory.ReadSecurityRegister() } -> std::same_as<uint8_t>;
|
||||
{ memory.ProgramFailed() } -> std::same_as<bool>;
|
||||
{ memory.EraseFailed() } -> std::same_as<bool>;
|
||||
{ memory.Init() };
|
||||
{ memory.Uninit() };
|
||||
{ memory.Sleep() };
|
||||
{ memory.Wakeup() };
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) Identification {
|
||||
uint8_t manufacturer = 0;
|
||||
uint8_t type = 0;
|
||||
uint8_t density = 0;
|
||||
namespace Interface {
|
||||
template <class T>
|
||||
requires IsFlashMemory<T>
|
||||
class SpiNorFlash {
|
||||
public:
|
||||
explicit SpiNorFlash(T& spi) : impl {spi} {
|
||||
}
|
||||
SpiNorFlash(const SpiNorFlash&) = delete;
|
||||
SpiNorFlash& operator=(const SpiNorFlash&) = delete;
|
||||
SpiNorFlash(SpiNorFlash&&) = delete;
|
||||
SpiNorFlash& operator=(SpiNorFlash&&) = delete;
|
||||
|
||||
struct __attribute__((packed)) Identification {
|
||||
uint8_t manufacturer = 0;
|
||||
uint8_t type = 0;
|
||||
uint8_t density = 0;
|
||||
};
|
||||
|
||||
Identification ReadIdentificaion() {
|
||||
return impl.ReadIdentificaion();
|
||||
}
|
||||
|
||||
uint8_t ReadStatusRegister() {
|
||||
return impl.ReadStatusRegister();
|
||||
}
|
||||
|
||||
bool WriteInProgress() {
|
||||
return impl.WriteInProgress();
|
||||
}
|
||||
|
||||
bool WriteEnabled() {
|
||||
return impl.WriteEnabled();
|
||||
}
|
||||
|
||||
uint8_t ReadConfigurationRegister() {
|
||||
return impl.ReadConfigurationRegister();
|
||||
}
|
||||
|
||||
void Read(uint32_t address, uint8_t* buffer, size_t size) {
|
||||
impl.Read(address, buffer, size);
|
||||
}
|
||||
|
||||
void Write(uint32_t address, const uint8_t* buffer, size_t size) {
|
||||
impl.Write(address, buffer, size);
|
||||
}
|
||||
|
||||
void WriteEnable() {
|
||||
return impl.WriteEnable();
|
||||
}
|
||||
|
||||
void SectorErase(uint32_t sectorAddress) {
|
||||
impl.SectorErase(sectorAddress);
|
||||
}
|
||||
|
||||
uint8_t ReadSecurityRegister() {
|
||||
return impl.ReadSecurityRegister();
|
||||
}
|
||||
|
||||
bool ProgramFailed() {
|
||||
return impl.ProgramFailed();
|
||||
}
|
||||
|
||||
bool EraseFailed() {
|
||||
return impl.EraseFailed();
|
||||
}
|
||||
|
||||
void Init() {
|
||||
impl.Init();
|
||||
}
|
||||
|
||||
void Uninit() {
|
||||
impl.Uninit();
|
||||
}
|
||||
|
||||
void Sleep() {
|
||||
impl.Sleep();
|
||||
}
|
||||
|
||||
void Wakeup() {
|
||||
impl.Wakeup();
|
||||
}
|
||||
|
||||
private:
|
||||
T& impl;
|
||||
};
|
||||
|
||||
Identification ReadIdentificaion();
|
||||
uint8_t ReadStatusRegister();
|
||||
bool WriteInProgress();
|
||||
bool WriteEnabled();
|
||||
uint8_t ReadConfigurationRegister();
|
||||
void Read(uint32_t address, uint8_t* buffer, size_t size);
|
||||
void Write(uint32_t address, const uint8_t* buffer, size_t size);
|
||||
void WriteEnable();
|
||||
void SectorErase(uint32_t sectorAddress);
|
||||
uint8_t ReadSecurityRegister();
|
||||
bool ProgramFailed();
|
||||
bool EraseFailed();
|
||||
|
||||
void Init();
|
||||
void Uninit();
|
||||
|
||||
void Sleep();
|
||||
void Wakeup();
|
||||
|
||||
private:
|
||||
enum class Commands : uint8_t {
|
||||
PageProgram = 0x02,
|
||||
Read = 0x03,
|
||||
ReadStatusRegister = 0x05,
|
||||
WriteEnable = 0x06,
|
||||
ReadConfigurationRegister = 0x15,
|
||||
SectorErase = 0x20,
|
||||
ReadSecurityRegister = 0x2B,
|
||||
ReadIdentification = 0x9F,
|
||||
ReleaseFromDeepPowerDown = 0xAB,
|
||||
DeepPowerDown = 0xB9
|
||||
};
|
||||
static constexpr uint16_t pageSize = 256;
|
||||
|
||||
Spi& spi;
|
||||
Identification device_id;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
#include "Spi.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "port/infinitime.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
class Spi;
|
||||
|
||||
class St7789 {
|
||||
public:
|
||||
explicit St7789(Spi& spi, uint8_t pinDataCommand);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
#include "drivers/Spi.h"
|
||||
#include "Spi.h"
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include <nrfx_log.h>
|
||||
|
||||
using namespace Pinetime::Drivers;
|
||||
using namespace Pinetime::Drivers::Nrf52;
|
||||
|
||||
Spi::Spi(SpiMaster& spiMaster, uint8_t pinCsn) : spiMaster {spiMaster}, pinCsn {pinCsn} {
|
||||
nrf_gpio_cfg_output(pinCsn);
|
||||
30
src/drivers/nrf52/Spi.h
Normal file
30
src/drivers/nrf52/Spi.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "drivers/nrf52/SpiMaster.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
namespace Nrf52 {
|
||||
class Spi {
|
||||
public:
|
||||
Spi(Pinetime::Drivers::Nrf52::SpiMaster& spiMaster, uint8_t pinCsn);
|
||||
Spi(const Spi&) = delete;
|
||||
Spi& operator=(const Spi&) = delete;
|
||||
Spi(Spi&&) = delete;
|
||||
Spi& operator=(Spi&&) = delete;
|
||||
|
||||
bool Init();
|
||||
bool Write(const uint8_t* data, size_t size);
|
||||
bool Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize);
|
||||
bool WriteCmdAndBuffer(const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize);
|
||||
void Sleep();
|
||||
void Wakeup();
|
||||
|
||||
private:
|
||||
Pinetime::Drivers::Nrf52::SpiMaster& spiMaster;
|
||||
uint8_t pinCsn;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
#include "drivers/SpiMaster.h"
|
||||
#include "SpiMaster.h"
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include <hal/nrf_spim.h>
|
||||
#include <nrfx_log.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Pinetime::Drivers;
|
||||
using namespace Pinetime::Drivers::Nrf52;
|
||||
|
||||
SpiMaster::SpiMaster(const SpiMaster::SpiModule spi, const SpiMaster::Parameters& params) : spi {spi}, params {params} {
|
||||
}
|
||||
67
src/drivers/nrf52/SpiMaster.h
Normal file
67
src/drivers/nrf52/SpiMaster.h
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
#include <task.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
namespace Nrf52 {
|
||||
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;
|
||||
};
|
||||
|
||||
SpiMaster(const SpiModule spi, const Parameters& params);
|
||||
SpiMaster(const SpiMaster&) = delete;
|
||||
SpiMaster& operator=(const SpiMaster&) = delete;
|
||||
SpiMaster(SpiMaster&&) = delete;
|
||||
SpiMaster& operator=(SpiMaster&&) = delete;
|
||||
|
||||
bool Init();
|
||||
bool Write(uint8_t pinCsn, const uint8_t* data, size_t size);
|
||||
bool Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize);
|
||||
|
||||
bool WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize);
|
||||
|
||||
void OnStartedEvent();
|
||||
void OnEndEvent();
|
||||
|
||||
void Sleep();
|
||||
void Wakeup();
|
||||
|
||||
private:
|
||||
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);
|
||||
void PrepareRx(const volatile uint32_t cmdAddress,
|
||||
const volatile size_t cmdSize,
|
||||
const volatile uint32_t bufferAddress,
|
||||
const volatile size_t size);
|
||||
|
||||
NRF_SPIM_Type* spiBaseAddress;
|
||||
uint8_t pinCsn;
|
||||
|
||||
SpiMaster::SpiModule spi;
|
||||
SpiMaster::Parameters params;
|
||||
|
||||
volatile uint32_t currentBufferAddr = 0;
|
||||
volatile size_t currentBufferSize = 0;
|
||||
volatile TaskHandle_t taskToNotify;
|
||||
SemaphoreHandle_t mutex = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,16 +1,16 @@
|
||||
#include "drivers/SpiNorFlash.h"
|
||||
#include "drivers/spiFlash/SpiNorFlash.h"
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include <libraries/delay/nrf_delay.h>
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include "drivers/Spi.h"
|
||||
|
||||
using namespace Pinetime::Drivers;
|
||||
using namespace Pinetime::Drivers::SpiFlash;
|
||||
|
||||
SpiNorFlash::SpiNorFlash(Spi& spi) : spi {spi} {
|
||||
SpiNorFlash::SpiNorFlash(Pinetime::Drivers::Nrf52::Spi& spi) : spi {spi} {
|
||||
}
|
||||
|
||||
void SpiNorFlash::Init() {
|
||||
device_id = ReadIdentificaion();
|
||||
device_id = ReadIdentification();
|
||||
NRF_LOG_INFO("[SpiNorFlash] Manufacturer : %d, Memory type : %d, memory density : %d",
|
||||
device_id.manufacturer,
|
||||
device_id.type,
|
||||
@ -32,7 +32,7 @@ void SpiNorFlash::Wakeup() {
|
||||
uint8_t cmd[cmdSize] = {static_cast<uint8_t>(Commands::ReleaseFromDeepPowerDown), 0x01, 0x02, 0x03};
|
||||
uint8_t id = 0;
|
||||
spi.Read(reinterpret_cast<uint8_t*>(&cmd), cmdSize, &id, 1);
|
||||
auto devId = device_id = ReadIdentificaion();
|
||||
auto devId = device_id = ReadIdentification();
|
||||
if (devId.type != device_id.type) {
|
||||
NRF_LOG_INFO("[SpiNorFlash] ID on Wakeup: Failed");
|
||||
} else {
|
||||
@ -41,7 +41,7 @@ void SpiNorFlash::Wakeup() {
|
||||
NRF_LOG_INFO("[SpiNorFlash] Wakeup")
|
||||
}
|
||||
|
||||
SpiNorFlash::Identification SpiNorFlash::ReadIdentificaion() {
|
||||
SpiNorFlash::Identification SpiNorFlash::ReadIdentification() {
|
||||
auto cmd = static_cast<uint8_t>(Commands::ReadIdentification);
|
||||
Identification identification;
|
||||
spi.Read(&cmd, 1, reinterpret_cast<uint8_t*>(&identification), sizeof(Identification));
|
||||
62
src/drivers/spiFlash/SpiNorFlash.h
Normal file
62
src/drivers/spiFlash/SpiNorFlash.h
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include "drivers/nrf52/Spi.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
namespace SpiFlash {
|
||||
class SpiNorFlash {
|
||||
public:
|
||||
explicit SpiNorFlash(Pinetime::Drivers::Nrf52::Spi& spi);
|
||||
SpiNorFlash(const SpiNorFlash&) = delete;
|
||||
SpiNorFlash& operator=(const SpiNorFlash&) = delete;
|
||||
SpiNorFlash(SpiNorFlash&&) = delete;
|
||||
SpiNorFlash& operator=(SpiNorFlash&&) = delete;
|
||||
|
||||
struct __attribute__((packed)) Identification {
|
||||
uint8_t manufacturer = 0;
|
||||
uint8_t type = 0;
|
||||
uint8_t density = 0;
|
||||
};
|
||||
|
||||
Identification ReadIdentification();
|
||||
uint8_t ReadStatusRegister();
|
||||
bool WriteInProgress();
|
||||
bool WriteEnabled();
|
||||
uint8_t ReadConfigurationRegister();
|
||||
void Read(uint32_t address, uint8_t* buffer, size_t size);
|
||||
void Write(uint32_t address, const uint8_t* buffer, size_t size);
|
||||
void WriteEnable();
|
||||
void SectorErase(uint32_t sectorAddress);
|
||||
uint8_t ReadSecurityRegister();
|
||||
bool ProgramFailed();
|
||||
bool EraseFailed();
|
||||
|
||||
void Init();
|
||||
void Uninit();
|
||||
|
||||
void Sleep();
|
||||
void Wakeup();
|
||||
|
||||
private:
|
||||
enum class Commands : uint8_t {
|
||||
PageProgram = 0x02,
|
||||
Read = 0x03,
|
||||
ReadStatusRegister = 0x05,
|
||||
WriteEnable = 0x06,
|
||||
ReadConfigurationRegister = 0x15,
|
||||
SectorErase = 0x20,
|
||||
ReadSecurityRegister = 0x2B,
|
||||
ReadIdentification = 0x9F,
|
||||
ReleaseFromDeepPowerDown = 0xAB,
|
||||
DeepPowerDown = 0xB9
|
||||
};
|
||||
static constexpr uint16_t pageSize = 256;
|
||||
|
||||
Pinetime::Drivers::Nrf52::Spi& spi;
|
||||
Identification device_id;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/main.cpp
27
src/main.cpp
@ -27,6 +27,7 @@
|
||||
#include <timers.h>
|
||||
#include <drivers/Hrs3300.h>
|
||||
#include <drivers/Bma421.h>
|
||||
#include <drivers/SpiMaster.h>
|
||||
|
||||
#include "BootloaderVersion.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
@ -37,8 +38,8 @@
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "components/heartrate/HeartRateController.h"
|
||||
#include "components/fs/FS.h"
|
||||
#include "drivers/Spi.h"
|
||||
#include "drivers/SpiMaster.h"
|
||||
#include "drivers/nrf52/Spi.h"
|
||||
#include "drivers/nrf52/SpiMaster.h"
|
||||
#include "drivers/SpiNorFlash.h"
|
||||
#include "drivers/St7789.h"
|
||||
#include "drivers/TwiMaster.h"
|
||||
@ -57,23 +58,31 @@ Pinetime::Logging::NrfLogger logger;
|
||||
Pinetime::Logging::DummyLogger logger;
|
||||
#endif
|
||||
|
||||
#include "port/infinitime.h"
|
||||
|
||||
static constexpr uint8_t touchPanelTwiAddress = 0x15;
|
||||
static constexpr uint8_t motionSensorTwiAddress = 0x18;
|
||||
static constexpr uint8_t heartRateSensorTwiAddress = 0x44;
|
||||
|
||||
Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0,
|
||||
{Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb,
|
||||
Pinetime::Drivers::SpiMaster::Modes::Mode3,
|
||||
Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz,
|
||||
Pinetime::Drivers::Nrf52::SpiMaster spiImpl {Pinetime::Drivers::Nrf52::SpiMaster::SpiModule::SPI0,
|
||||
{Pinetime::Drivers::Nrf52::SpiMaster::BitOrder::Msb_Lsb,
|
||||
Pinetime::Drivers::Nrf52::SpiMaster::Modes::Mode3,
|
||||
Pinetime::Drivers::Nrf52::SpiMaster::Frequencies::Freq8Mhz,
|
||||
Pinetime::PinMap::SpiSck,
|
||||
Pinetime::PinMap::SpiMosi,
|
||||
Pinetime::PinMap::SpiMiso}};
|
||||
|
||||
Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn};
|
||||
Pinetime::Drivers::SpiMaster spi {spiImpl};
|
||||
|
||||
Pinetime::Drivers::Nrf52::Spi lcdSpiIpmpl {spiImpl, Pinetime::PinMap::SpiLcdCsn};
|
||||
Pinetime::Drivers::Spi lcdSpi {lcdSpiIpmpl};
|
||||
Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand};
|
||||
|
||||
Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn};
|
||||
Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi};
|
||||
Pinetime::Drivers::Nrf52::Spi flashSpiImpl {spiImpl, Pinetime::PinMap::SpiFlashCsn};
|
||||
Pinetime::Drivers::Spi flashSpi {flashSpiImpl};
|
||||
|
||||
Pinetime::Drivers::SpiFlash::SpiNorFlash spiNorFlashImpl{flashSpiImpl};
|
||||
Pinetime::Drivers::SpiNorFlash spiNorFlash {spiNorFlashImpl};
|
||||
|
||||
// The TWI device should work @ up to 400Khz but there is a HW bug which prevent it from
|
||||
// respecting correct timings. According to erratas heet, this magic value makes it run
|
||||
|
||||
24
src/port/infinitime.h
Normal file
24
src/port/infinitime.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "drivers/Spi.h"
|
||||
#include "drivers/SpiMaster.h"
|
||||
#include <cstdint>
|
||||
#include <drivers/SpiNorFlash.h>
|
||||
|
||||
#ifdef TARGET_DEVICE_PINETIME
|
||||
#include <drivers/nrf52/Spi.h>
|
||||
#include <drivers/nrf52/SpiMaster.h>
|
||||
#include <drivers/spiFlash/SpiNorFlash.h>
|
||||
#endif
|
||||
|
||||
// #error "Do not include this"
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
#ifdef TARGET_DEVICE_PINETIME
|
||||
using SpiMaster = Interface::SpiMaster<Pinetime::Drivers::Nrf52::SpiMaster>;
|
||||
using Spi = Interface::Spi<Pinetime::Drivers::Nrf52::Spi>;
|
||||
using SpiNorFlash = Interface::SpiNorFlash<Pinetime::Drivers::SpiFlash::SpiNorFlash>;
|
||||
#else
|
||||
#error "No target device specified!"
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,7 @@
|
||||
#include <drivers/Bma421.h>
|
||||
#include <drivers/PinMap.h>
|
||||
#include <components/motion/MotionController.h>
|
||||
#include <drivers/SpiMaster.h>
|
||||
|
||||
#include "systemtask/SystemMonitor.h"
|
||||
#include "components/ble/NimbleController.h"
|
||||
@ -34,13 +35,12 @@
|
||||
|
||||
#include "drivers/Watchdog.h"
|
||||
#include "systemtask/Messages.h"
|
||||
#include "port/infinitime.h"
|
||||
|
||||
extern std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime;
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
class Cst816S;
|
||||
class SpiMaster;
|
||||
class SpiNorFlash;
|
||||
class St7789;
|
||||
class TwiMaster;
|
||||
class Hrs3300;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user