ref: 0.12.0
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 |
#include "SpiNorFlash.h" #include <hal/nrf_gpio.h> #include <libraries/delay/nrf_delay.h> #include <libraries/log/nrf_log.h> #include "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), (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; } } |