diff options
author | JF <jf@codingfield.com> | 2020-06-07 14:17:45 +0200 |
---|---|---|
committer | Gitea <gitea@fake.local> | 2020-06-07 14:17:45 +0200 |
commit | a0e73f5c1a1e652aa6270b7e42a73aee3d12ded6 (patch) | |
tree | 6205dfb543bb22245d39a2f6e44d2c26cb381c10 /src/drivers | |
parent | 8a94750e30399bfb204cbec59a769d9d1b6b5baa (diff) | |
parent | dbdb26ae1fa45cec88f1b9ea0353b3d0a3c39f56 (diff) |
Merge branch 'develop' of JF/PineTime into master
Diffstat (limited to 'src/drivers')
-rw-r--r-- | src/drivers/InternalFlash.cpp | 39 | ||||
-rw-r--r-- | src/drivers/InternalFlash.h | 15 | ||||
-rw-r--r-- | src/drivers/Spi.cpp | 34 | ||||
-rw-r--r-- | src/drivers/Spi.h | 34 | ||||
-rw-r--r-- | src/drivers/SpiMaster.cpp | 96 | ||||
-rw-r--r-- | src/drivers/SpiMaster.h | 8 | ||||
-rw-r--r-- | src/drivers/SpiNorFlash.cpp | 124 | ||||
-rw-r--r-- | src/drivers/SpiNorFlash.h | 60 | ||||
-rw-r--r-- | src/drivers/St7789.cpp | 9 | ||||
-rw-r--r-- | src/drivers/St7789.h | 6 |
10 files changed, 408 insertions, 17 deletions
diff --git a/src/drivers/InternalFlash.cpp b/src/drivers/InternalFlash.cpp new file mode 100644 index 00000000..bc89ff1a --- /dev/null +++ b/src/drivers/InternalFlash.cpp @@ -0,0 +1,39 @@ +#include <sdk/modules/nrfx/mdk/nrf.h> +#include "InternalFlash.h" +using namespace Pinetime::Drivers; + +void InternalFlash::ErasePage(uint32_t address) { + // Enable erase. + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een; + __ISB(); + __DSB(); + + // Erase the page + NRF_NVMC->ERASEPAGE = address; + Wait(); + + // Disable erase + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren; + __ISB(); + __DSB(); +} + +void InternalFlash::WriteWord(uint32_t address, uint32_t value) { + // Enable write. + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen; + __ISB(); + __DSB(); + + // Write word + *(uint32_t*)address = value; + Wait(); + + // Disable write + NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren; + __ISB(); + __DSB(); +} + +void InternalFlash::Wait() { + while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {;} +} diff --git a/src/drivers/InternalFlash.h b/src/drivers/InternalFlash.h new file mode 100644 index 00000000..fd25bf46 --- /dev/null +++ b/src/drivers/InternalFlash.h @@ -0,0 +1,15 @@ +#pragma once + +#include <cstdint> + +namespace Pinetime { + namespace Drivers { + class InternalFlash { + public: + static void ErasePage(uint32_t address); + static void WriteWord(uint32_t address, uint32_t value); + private: + static inline void Wait(); + }; + } +}
\ No newline at end of file diff --git a/src/drivers/Spi.cpp b/src/drivers/Spi.cpp new file mode 100644 index 00000000..bf08178d --- /dev/null +++ b/src/drivers/Spi.cpp @@ -0,0 +1,34 @@ +#include <hal/nrf_gpio.h> +#include "Spi.h" + +using namespace Pinetime::Drivers; + +Spi::Spi(SpiMaster& spiMaster, uint8_t pinCsn) : + spiMaster{spiMaster}, pinCsn{pinCsn} { + nrf_gpio_cfg_output(pinCsn); + nrf_gpio_pin_set(pinCsn); +} + +bool Spi::Write(const uint8_t *data, size_t size) { + return spiMaster.Write(pinCsn, data, size); +} + +bool Spi::Read(uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize) { + return spiMaster.Read(pinCsn, cmd, cmdSize, data, dataSize); +} + +void Spi::Sleep() { + // TODO sleep spi + nrf_gpio_cfg_default(pinCsn); +} + +bool Spi::Init() { + nrf_gpio_pin_set(pinCsn); /* disable Set slave select (inactive high) */ + return true; +} + +bool Spi::WriteCmdAndBuffer(const uint8_t *cmd, size_t cmdSize, const uint8_t *data, size_t dataSize) { + return spiMaster.WriteCmdAndBuffer(pinCsn, cmd, cmdSize, data, dataSize); +} + + diff --git a/src/drivers/Spi.h b/src/drivers/Spi.h new file mode 100644 index 00000000..82ba8a65 --- /dev/null +++ b/src/drivers/Spi.h @@ -0,0 +1,34 @@ +#pragma once +#include <FreeRTOS.h> +#include <cstdint> +#include <cstddef> +#include <array> +#include <atomic> +#include <task.h> + +#include "BufferProvider.h" +#include "SpiMaster.h" + +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; + + 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: + SpiMaster& spiMaster; + uint8_t pinCsn; + }; + } +} diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 4b3dd677..8087d386 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -9,8 +9,8 @@ using namespace Pinetime::Drivers; SpiMaster::SpiMaster(const SpiMaster::SpiModule spi, const SpiMaster::Parameters ¶ms) : spi{spi}, params{params} { - mutex = xSemaphoreCreateBinary(); - ASSERT(mutex != NULL); + mutex = xSemaphoreCreateBinary(); + ASSERT(mutex != NULL); } bool SpiMaster::Init() { @@ -20,8 +20,8 @@ bool SpiMaster::Init() { nrf_gpio_pin_clear(params.pinMOSI); nrf_gpio_cfg_output(params.pinMOSI); nrf_gpio_cfg_input(params.pinMISO, NRF_GPIO_PIN_NOPULL); - nrf_gpio_cfg_output(params.pinCSN); - pinCsn = params.pinCSN; +// nrf_gpio_cfg_output(params.pinCSN); +// pinCsn = params.pinCSN; switch(spi) { case SpiModule::SPI0: spiBaseAddress = NRF_SPIM0; break; @@ -33,7 +33,6 @@ bool SpiMaster::Init() { 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) { @@ -147,19 +146,33 @@ void SpiMaster::PrepareTx(const volatile uint32_t bufferAddress, const volatile spiBaseAddress->EVENTS_END = 0; } -bool SpiMaster::Write(const uint8_t *data, size_t size) { +void SpiMaster::PrepareRx(const volatile uint32_t cmdAddress, const volatile size_t cmdSize, const volatile uint32_t bufferAddress, const volatile size_t size) { + spiBaseAddress->TXD.PTR = 0; + spiBaseAddress->TXD.MAXCNT = 0; + spiBaseAddress->TXD.LIST = 0; + spiBaseAddress->RXD.PTR = bufferAddress; + spiBaseAddress->RXD.MAXCNT = size; + spiBaseAddress->RXD.LIST = 0; + spiBaseAddress->EVENTS_END = 0; +} + + +bool SpiMaster::Write(uint8_t pinCsn, const uint8_t *data, size_t size) { if(data == nullptr) return false; auto ok = xSemaphoreTake(mutex, portMAX_DELAY); ASSERT(ok == true); taskToNotify = xTaskGetCurrentTaskHandle(); + + this->pinCsn = pinCsn; + if(size == 1) { SetupWorkaroundForFtpan58(spiBaseAddress, 0,0); } else { DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); } - nrf_gpio_pin_clear(pinCsn); + nrf_gpio_pin_clear(this->pinCsn); currentBufferAddr = (uint32_t)data; currentBufferSize = size; @@ -172,12 +185,47 @@ bool SpiMaster::Write(const uint8_t *data, size_t size) { if(size == 1) { while (spiBaseAddress->EVENTS_END == 0); + nrf_gpio_pin_set(this->pinCsn); + currentBufferAddr = 0; xSemaphoreGive(mutex); } return true; } +bool SpiMaster::Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t *data, size_t dataSize) { + xSemaphoreTake(mutex, portMAX_DELAY); + + taskToNotify = nullptr; + + this->pinCsn = pinCsn; + DisableWorkaroundForFtpan58(spiBaseAddress, 0,0); + spiBaseAddress->INTENCLR = (1<<6); + spiBaseAddress->INTENCLR = (1<<1); + spiBaseAddress->INTENCLR = (1<<19); + + nrf_gpio_pin_clear(this->pinCsn); + + + currentBufferAddr = 0; + currentBufferSize = 0; + + PrepareTx((uint32_t)cmd, cmdSize); + spiBaseAddress->TASKS_START = 1; + while (spiBaseAddress->EVENTS_END == 0); + + PrepareRx((uint32_t)cmd, cmdSize, (uint32_t)data, dataSize); + spiBaseAddress->TASKS_START = 1; + + while (spiBaseAddress->EVENTS_END == 0); + nrf_gpio_pin_set(this->pinCsn); + + xSemaphoreGive(mutex); + + return true; +} + + void SpiMaster::Sleep() { while(spiBaseAddress->ENABLE != 0) { spiBaseAddress->ENABLE = (SPIM_ENABLE_ENABLE_Disabled << SPIM_ENABLE_ENABLE_Pos); @@ -185,11 +233,43 @@ void SpiMaster::Sleep() { nrf_gpio_cfg_default(params.pinSCK); nrf_gpio_cfg_default(params.pinMOSI); nrf_gpio_cfg_default(params.pinMISO); - nrf_gpio_cfg_default(params.pinCSN); } void SpiMaster::Wakeup() { Init(); } +bool SpiMaster::WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t *cmd, size_t cmdSize, const uint8_t *data, size_t dataSize) { + xSemaphoreTake(mutex, portMAX_DELAY); + + taskToNotify = nullptr; + + this->pinCsn = pinCsn; + DisableWorkaroundForFtpan58(spiBaseAddress, 0,0); + spiBaseAddress->INTENCLR = (1<<6); + spiBaseAddress->INTENCLR = (1<<1); + spiBaseAddress->INTENCLR = (1<<19); + + nrf_gpio_pin_clear(this->pinCsn); + + + currentBufferAddr = 0; + currentBufferSize = 0; + + PrepareTx((uint32_t)cmd, cmdSize); + spiBaseAddress->TASKS_START = 1; + while (spiBaseAddress->EVENTS_END == 0); + + PrepareTx((uint32_t)data, dataSize); + spiBaseAddress->TASKS_START = 1; + + while (spiBaseAddress->EVENTS_END == 0); + nrf_gpio_pin_set(this->pinCsn); + + xSemaphoreGive(mutex); + + return true; +} + + diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 8a633b7f..cd3193e4 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -5,6 +5,7 @@ #include <array> #include <atomic> #include <task.h> +#include <semphr.h> #include "BufferProvider.h" #include <semphr.h> @@ -24,7 +25,6 @@ namespace Pinetime { uint8_t pinSCK; uint8_t pinMOSI; uint8_t pinMISO; - uint8_t pinCSN; }; SpiMaster(const SpiModule spi, const Parameters& params); @@ -34,7 +34,10 @@ namespace Pinetime { SpiMaster& operator=(SpiMaster&&) = delete; bool Init(); - bool Write(const uint8_t* data, size_t size); + 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(); @@ -46,6 +49,7 @@ namespace Pinetime { 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; diff --git a/src/drivers/SpiNorFlash.cpp b/src/drivers/SpiNorFlash.cpp new file mode 100644 index 00000000..7e4da1ca --- /dev/null +++ b/src/drivers/SpiNorFlash.cpp @@ -0,0 +1,124 @@ +#include <hal/nrf_gpio.h> +#include <libraries/delay/nrf_delay.h> +#include <libraries/log/nrf_log.h> +#include "SpiNorFlash.h" +#include "Spi.h" + +using namespace Pinetime::Drivers; + +SpiNorFlash::SpiNorFlash(Spi& spi) : spi{spi} { + +} + +void SpiNorFlash::Init() { + auto id = ReadIdentificaion(); + NRF_LOG_INFO("[SPI FLASH] Manufacturer : %d, Memory type : %d, memory density : %d", id.manufacturer, id.type, id.density); +} + +void SpiNorFlash::Uninit() { + +} + +void SpiNorFlash::Sleep() { + +} + +void SpiNorFlash::Wakeup() { + +} + +SpiNorFlash::Identification SpiNorFlash::ReadIdentificaion() { + auto cmd = static_cast<uint8_t>(Commands::ReadIdentification); + Identification identification; + spi.Read(&cmd, 1, reinterpret_cast<uint8_t *>(&identification), sizeof(Identification)); + return identification; +} + +uint8_t SpiNorFlash::ReadStatusRegister() { + auto cmd = static_cast<uint8_t>(Commands::ReadStatusRegister); + uint8_t status; + spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t)); + return status; +} + +bool SpiNorFlash::WriteInProgress() { + return (ReadStatusRegister() & 0x01u) == 0x01u; +} + +bool SpiNorFlash::WriteEnabled() { + return (ReadStatusRegister() & 0x02u) == 0x02u; +} + +uint8_t SpiNorFlash::ReadConfigurationRegister() { + auto cmd = static_cast<uint8_t>(Commands::ReadConfigurationRegister); + uint8_t status; + spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t)); + return status; +} + +void SpiNorFlash::Read(uint32_t address, uint8_t *buffer, size_t size) { + static constexpr uint8_t cmdSize = 4; + uint8_t cmd[cmdSize] = { static_cast<uint8_t>(Commands::Read), (uint8_t)(address >> 16U), (uint8_t)(address >> 8U), + (uint8_t)address }; + spi.Read(reinterpret_cast<uint8_t *>(&cmd), cmdSize, buffer, size); +} + +void SpiNorFlash::WriteEnable() { + auto cmd = static_cast<uint8_t>(Commands::WriteEnable); + spi.Read(&cmd, sizeof(cmd), nullptr, 0); +} + +void SpiNorFlash::SectorErase(uint32_t sectorAddress) { + static constexpr uint8_t cmdSize = 4; + uint8_t cmd[cmdSize] = { static_cast<uint8_t>(Commands::SectorErase), (uint8_t)(sectorAddress >> 16U), (uint8_t)(sectorAddress >> 8U), + (uint8_t)sectorAddress }; + + WriteEnable(); + while(!WriteEnabled()) vTaskDelay(1); + + spi.Read(reinterpret_cast<uint8_t *>(&cmd), cmdSize, nullptr, 0); + + while(WriteInProgress()) vTaskDelay(1); +} + +uint8_t SpiNorFlash::ReadSecurityRegister() { + auto cmd = static_cast<uint8_t>(Commands::ReadSecurityRegister); + uint8_t status; + spi.Read(&cmd, sizeof(cmd), &status, sizeof(uint8_t)); + return status; +} + +bool SpiNorFlash::ProgramFailed() { + return (ReadSecurityRegister() & 0x20u) == 0x20u; +} + +bool SpiNorFlash::EraseFailed() { + return (ReadSecurityRegister() & 0x40u) == 0x40u; +} + +void SpiNorFlash::Write(uint32_t address, const uint8_t *buffer, size_t size) { + static constexpr uint8_t cmdSize = 4; + + size_t len = size; + uint32_t addr = address; + const uint8_t* b = buffer; + while(len > 0) { + uint32_t pageLimit = (addr & ~(pageSize - 1u)) + pageSize; + uint32_t toWrite = pageLimit - addr > len ? len : pageLimit - addr; + + uint8_t cmd[cmdSize] = { static_cast<uint8_t>(Commands::PageProgram), (uint8_t)(addr >> 16U), (uint8_t)(addr >> 8U), + (uint8_t)addr }; + + WriteEnable(); + while(!WriteEnabled()) vTaskDelay(1); + + spi.WriteCmdAndBuffer(cmd, cmdSize, b, toWrite); + + while(WriteInProgress()) vTaskDelay(1); + + addr += toWrite; + b += toWrite; + len -= toWrite; + } + +} diff --git a/src/drivers/SpiNorFlash.h b/src/drivers/SpiNorFlash.h new file mode 100644 index 00000000..98267c09 --- /dev/null +++ b/src/drivers/SpiNorFlash.h @@ -0,0 +1,60 @@ +#pragma once +#include <cstddef> + +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; + + typedef struct __attribute__((packed)) { + uint8_t manufacturer = 0; + uint8_t type = 0; + uint8_t density = 0; + } Identification; + + 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, + }; + static constexpr uint16_t pageSize = 256; + + Spi& spi; + + }; + } +} + + diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index db7c27e2..09269afd 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -1,16 +1,17 @@ #include <hal/nrf_gpio.h> #include <libraries/delay/nrf_delay.h> #include "St7789.h" -#include "SpiMaster.h" +#include "Spi.h" using namespace Pinetime::Drivers; -St7789::St7789(SpiMaster &spiMaster, uint8_t pinDataCommand) : spi{spiMaster}, pinDataCommand{pinDataCommand} { +St7789::St7789(Spi &spi, uint8_t pinDataCommand) : spi{spi}, pinDataCommand{pinDataCommand} { } void St7789::Init() { + spi.Init(); nrf_gpio_cfg_output(pinDataCommand); nrf_gpio_cfg_output(26); nrf_gpio_pin_set(26); @@ -173,11 +174,11 @@ void St7789::HardwareReset() { void St7789::Sleep() { SleepIn(); nrf_gpio_cfg_default(pinDataCommand); - spi.Sleep(); +// spi.Sleep(); // TODO sleep SPI } void St7789::Wakeup() { - spi.Wakeup(); +// spi.Wakeup(); // TODO wake up SPI nrf_gpio_cfg_output(pinDataCommand); // TODO why do we need to reset the controller? diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 3721b184..0b94cf24 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -3,10 +3,10 @@ namespace Pinetime { namespace Drivers { - class SpiMaster; + class Spi; class St7789 { public: - explicit St7789(SpiMaster& spiMaster, uint8_t pinDataCommand); + explicit St7789(Spi& spi, uint8_t pinDataCommand); St7789(const St7789&) = delete; St7789& operator=(const St7789&) = delete; St7789(St7789&&) = delete; @@ -29,7 +29,7 @@ namespace Pinetime { void Sleep(); void Wakeup(); private: - SpiMaster& spi; + Spi& spi; uint8_t pinDataCommand; uint8_t verticalScrollingStartAddress = 0; |