// Transfer Address. bool SPIFlash::_transferAddress(void) { if (address4ByteEnabled) { _nextByte(WRITE, Highest(_currentAddress)); } _nextByte(WRITE, Higher(_currentAddress)); _nextByte(WRITE, Hi(_currentAddress)); _nextByte(WRITE, Lo(_currentAddress)); return true; }
// Returns a 64-bit Unique ID that is unique to each flash memory chip uint64_t SPIFram::getUniqueID(void) { _beginSPI(FRAMSERNO); for (uint8_t i = 0; i < 4; i++) { _nextByte(WRITE, DUMMYBYTE); } for (uint8_t i = 0; i < 8; i++) { _uniqueID[i] = _nextByte(READ); } CHIP_DESELECT long long _uid = 0; for (uint8_t i = 0; i < 8; i++) { _uid += _uniqueID[i]; _uid = _uid << 8; } return _uid; }
// Writes an array of bytes starting from a specific location in a page. // Takes four arguments - // 1. _addr --> Any address - from 0 to capacity // 2. data_buffer --> The pointer to the array of bytes be written to a particular location on a page // 3. bufferSize --> Size of the array of bytes - in number of bytes // 4. errorCheck --> Turned on by default. Checks for writing errors // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFram::writeByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif if(_isChipPoweredDown() || !_addressCheck(_addr, bufferSize) || !_notPrevWritten(_addr, bufferSize) || !_writeEnable()) { return false; } uint16_t maxBytes = SPI_PAGESIZE-(_addr % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page if (bufferSize <= maxBytes) { CHIP_SELECT _nextByte(WRITE, PAGEPROG); _transferAddress(); //_nextBuf(PAGEPROG, &data_buffer[0], bufferSize); for (uint16_t i = 0; i < bufferSize; ++i) { _nextByte(WRITE, data_buffer[i]); } CHIP_DESELECT }
// Writes a char of data to a specific location in a page. // Takes three arguments - // 1. _addr --> Any address - from 0 to capacity // 2. data --> One char to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFram::writeChar(uint32_t _addr, int8_t data, bool errorCheck) { //return _write(_addr, data, sizeof(data), errorCheck, _CHAR_); #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif if(_isChipPoweredDown() || !_addressCheck(_addr, sizeof(data)) || !_notPrevWritten(_addr, sizeof(data)) || !_writeEnable()) { return false; } _beginSPI(PAGEPROG); _nextByte(WRITE, data); CHIP_DESELECT if (!errorCheck) { _endSPI(); #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; #endif return true; } else { _currentAddress = _addr; CHIP_SELECT _nextByte(WRITE, READDATA); _transferAddress(); if (data != (int8_t)_nextByte(READ)) { _endSPI(); #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; #endif return false; } else { _endSPI(); #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; #endif return true; } } return true; }
// Checks to see if the block of memory has been previously written to bool SPIFlash::_notPrevWritten(uint32_t _addr, uint32_t size) { //uint8_t _dat; _beginSPI(READDATA); for (uint32_t i = 0; i < size; i++) { if (_nextByte(READ) != 0xFF) { CHIP_DESELECT; _troubleshoot(PREVWRITTEN); return false; } } CHIP_DESELECT return true; }
void ufdbEncryptText( ufdbCrypt * uc, unsigned char * dest, const unsigned char * src, unsigned int len ) { while (len > 0) { *dest = *src ^ _nextByte( uc ); src++; dest++; len--; } }
//Initiates SPI operation - but data is not transferred yet. Always call _prep() before this function (especially when it involves writing or reading to/from an address) bool SPIFlash::_beginSPI(uint8_t opcode) { if (!SPIBusState) { _startSPIBus(); } CHIP_SELECT switch (opcode) { case READDATA: _nextByte(WRITE, opcode); _transferAddress(); break; case PAGEPROG: _nextByte(WRITE, opcode); _transferAddress(); break; case FASTREAD: _nextByte(WRITE, opcode); _nextByte(WRITE, DUMMYBYTE); _transferAddress(); break; case SECTORERASE: _nextByte(WRITE, opcode); _transferAddress(); break; case BLOCK32ERASE: _nextByte(WRITE, opcode); _transferAddress(); break; case BLOCK64ERASE: _nextByte(WRITE, opcode); _transferAddress(); break; default: _nextByte(WRITE, opcode); break; } return true; }