ref: e5b73212f6addcfdb5e306df63d7135e543c4f8d
src/drivers/SpiNorFlash.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
#include "drivers/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; SpiNorFlash::SpiNorFlash(Spi& spi) : spi {spi} { } void SpiNorFlash::Init() { device_id = ReadIdentificaion(); NRF_LOG_INFO("[SpiNorFlash] Manufacturer : %d, Memory type : %d, memory density : %d", device_id.manufacturer, device_id.type, device_id.density); } void SpiNorFlash::Uninit() { } void SpiNorFlash::Sleep() { auto cmd = static_cast<uint8_t>(Commands::DeepPowerDown); spi.Write(&cmd, sizeof(uint8_t)); NRF_LOG_INFO("[SpiNorFlash] Sleep") } void SpiNorFlash::Wakeup() { // send Commands::ReleaseFromDeepPowerDown then 3 dummy bytes before reading Device ID static constexpr uint8_t cmdSize = 4; 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(); if (devId.type != device_id.type) { NRF_LOG_INFO("[SpiNorFlash] ID on Wakeup: Failed"); } else { NRF_LOG_INFO("[SpiNorFlash] ID on Wakeup: %d", id); } NRF_LOG_INFO("[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), static_cast<uint8_t>(address >> 16U), static_cast<uint8_t>(address >> 8U), static_cast<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), static_cast<uint8_t>(sectorAddress >> 16U), static_cast<uint8_t>(sectorAddress >> 8U), static_cast<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), static_cast<uint8_t>(addr >> 16U), static_cast<uint8_t>(addr >> 8U), static_cast<uint8_t>(addr)}; WriteEnable(); while (!WriteEnabled()) vTaskDelay(1); spi.WriteCmdAndBuffer(cmd, cmdSize, b, toWrite); while (WriteInProgress()) vTaskDelay(1); addr += toWrite; b += toWrite; len -= toWrite; } } |