mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
269 lines
5.2 KiB
C++
269 lines
5.2 KiB
C++
//
|
|
// FILE: FRAM.cpp
|
|
// AUTHOR: Rob Tillaart
|
|
// VERSION: 0.3.1
|
|
// DATE: 2018-01-24
|
|
// PURPOSE: Arduino library for I2C FRAM
|
|
// URL: https://github.com/RobTillaart/FRAM_I2C
|
|
//
|
|
// HISTORY:
|
|
// 0.1.0 2018-01-24 initial version
|
|
// 0.1.1 2019-07-31 added suppport for Fujitsu 64Kbit MB85RC64T (kudos ysoyipek)
|
|
// 0.2.0 2020-04-30 refactor, add writeProtectPin code
|
|
// 0.2.1 2020-06-10 fix library.json
|
|
// 0.2.2 2020-12-23 arduino-CI + unit test + getWriteProtect()
|
|
// 0.2.3 2021-01-ii fix getMetaData (kudos to PraxisSoft
|
|
// 0.3.0 2021-01-13 fix #2 ESP32 + WireN support
|
|
// 0.3.1 2021-02-05 fix #7 typo in .cpp
|
|
|
|
|
|
#include "FRAM.h"
|
|
|
|
|
|
const uint8_t FRAM_SLAVE_ID_= 0x7C;
|
|
|
|
/////////////////////////////////////////////////////
|
|
//
|
|
// PUBLIC
|
|
//
|
|
FRAM::FRAM(TwoWire *wire)
|
|
{
|
|
_wire = wire;
|
|
_address = 0x50;
|
|
_writeProtectPin = -1;
|
|
}
|
|
|
|
|
|
#if defined (ESP8266) || defined(ESP32)
|
|
int FRAM::begin(uint8_t sda, uint8_t scl, const uint8_t address, int8_t writeProtectPin)
|
|
{
|
|
if (address < 0x50 || address > 0x57) return FRAM_ERROR_ADDR;
|
|
|
|
_wire = &Wire;
|
|
_address = address;
|
|
if ((sda < 255) && (scl < 255))
|
|
{
|
|
_wire->begin(sda, scl);
|
|
} else {
|
|
_wire->begin();
|
|
}
|
|
|
|
if (writeProtectPin > -1)
|
|
{
|
|
_writeProtectPin = writeProtectPin;
|
|
pinMode(_writeProtectPin, OUTPUT);
|
|
}
|
|
if (! isConnected()) return FRAM_ERROR_CONNECT;
|
|
return FRAM_OK;
|
|
}
|
|
#endif
|
|
|
|
|
|
int FRAM::begin(uint8_t address, int8_t writeProtectPin)
|
|
{
|
|
if (address < 0x50 || address > 0x57) return FRAM_ERROR_ADDR;
|
|
|
|
_address = address;
|
|
_wire->begin();
|
|
|
|
if (writeProtectPin > -1)
|
|
{
|
|
_writeProtectPin = writeProtectPin;
|
|
pinMode(_writeProtectPin, OUTPUT);
|
|
}
|
|
if (! isConnected()) return FRAM_ERROR_CONNECT;
|
|
return FRAM_OK;
|
|
}
|
|
|
|
|
|
bool FRAM::isConnected()
|
|
{
|
|
_wire->beginTransmission(_address);
|
|
return (_wire->endTransmission() == 0);
|
|
}
|
|
|
|
|
|
void FRAM::write8(uint16_t memaddr, uint8_t value)
|
|
{
|
|
uint8_t val = value;
|
|
writeBlock(memaddr, (uint8_t *)&val, 1);
|
|
}
|
|
|
|
|
|
void FRAM::write16(uint16_t memaddr, uint16_t value)
|
|
{
|
|
uint16_t val = value;
|
|
writeBlock(memaddr, (uint8_t *)&val, 2);
|
|
}
|
|
|
|
|
|
void FRAM::write32(uint16_t memaddr, uint32_t value)
|
|
{
|
|
uint32_t val = value;
|
|
writeBlock(memaddr, (uint8_t *)&val, 4);
|
|
}
|
|
|
|
|
|
void FRAM::write(uint16_t memaddr, uint8_t * obj, uint16_t size)
|
|
{
|
|
const int blocksize = 24;
|
|
uint8_t * p = obj;
|
|
while (size >= blocksize)
|
|
{
|
|
writeBlock(memaddr, p, blocksize);
|
|
memaddr += blocksize;
|
|
p += blocksize;
|
|
size -= blocksize;
|
|
}
|
|
// remaining
|
|
if (size > 0)
|
|
{
|
|
writeBlock(memaddr, p, size);
|
|
}
|
|
}
|
|
|
|
|
|
uint8_t FRAM::read8(uint16_t memaddr)
|
|
{
|
|
uint8_t val;
|
|
readBlock(memaddr, (uint8_t *)&val, 1);
|
|
return val;
|
|
}
|
|
|
|
|
|
uint16_t FRAM::read16(uint16_t memaddr)
|
|
{
|
|
uint16_t val;
|
|
readBlock(memaddr, (uint8_t *)&val, 2);
|
|
return val;
|
|
}
|
|
|
|
|
|
uint32_t FRAM::read32(uint16_t memaddr)
|
|
{
|
|
uint32_t val;
|
|
readBlock(memaddr, (uint8_t *)&val, 4);
|
|
return val;
|
|
}
|
|
|
|
|
|
void FRAM::read(uint16_t memaddr, uint8_t * obj, uint16_t size)
|
|
{
|
|
const uint8_t blocksize = 24;
|
|
uint8_t * p = obj;
|
|
while (size >= blocksize)
|
|
{
|
|
readBlock(memaddr, p, blocksize);
|
|
memaddr += blocksize;
|
|
p += blocksize;
|
|
size -= blocksize;
|
|
}
|
|
// remainder
|
|
if (size > 0)
|
|
{
|
|
readBlock(memaddr, p, size);
|
|
}
|
|
}
|
|
|
|
|
|
bool FRAM::setWriteProtect(bool b)
|
|
{
|
|
if (_writeProtectPin < 0) return false;
|
|
digitalWrite(_writeProtectPin, b ? HIGH : LOW);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool FRAM::getWriteProtect()
|
|
{
|
|
if (_writeProtectPin < 0) return false;
|
|
return (digitalRead(_writeProtectPin) == HIGH);
|
|
}
|
|
|
|
|
|
uint16_t FRAM::getManufacturerID()
|
|
{
|
|
return getMetaData(0);
|
|
}
|
|
|
|
|
|
uint16_t FRAM::getProductID()
|
|
{
|
|
return getMetaData(1);
|
|
}
|
|
|
|
|
|
uint16_t FRAM::getSize()
|
|
{
|
|
uint16_t val = getMetaData(2); // density bits
|
|
if (val > 0) return 1UL << val;
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// PRIVATE
|
|
//
|
|
|
|
// metadata is packed as [....MMMM][MMMMDDDD][PPPPPPPP]
|
|
// M = manufacturerID
|
|
// D = density => memsize = 2^D KB
|
|
// P = product ID (together with D)
|
|
uint16_t FRAM::getMetaData(uint8_t field)
|
|
{
|
|
if (field > 2) return 0;
|
|
|
|
_wire->beginTransmission(FRAM_SLAVE_ID_);
|
|
_wire->write(_address << 1);
|
|
_wire->endTransmission(false);
|
|
int x = _wire->requestFrom(FRAM_SLAVE_ID_, (uint8_t)3);
|
|
if (x != 3) return -1;
|
|
|
|
uint32_t value = 0;
|
|
value = _wire->read();
|
|
value = value << 8;
|
|
value |= _wire->read();
|
|
value = value << 8;
|
|
value |= _wire->read();
|
|
|
|
// MANUFACTURER
|
|
if (field == 0) return (value >> 12) & 0xFF;
|
|
// PRODUCT ID
|
|
if (field == 1) return value & 0x0FFF;
|
|
// DENSITY
|
|
if (field == 2) return (value >> 8) & 0x0F;
|
|
return 0;
|
|
}
|
|
|
|
|
|
void FRAM::writeBlock(uint16_t memaddr, uint8_t * obj, uint8_t size)
|
|
{
|
|
// TODO constrain size < 30 ??
|
|
_wire->beginTransmission(_address);
|
|
_wire->write(memaddr >> 8);
|
|
_wire->write(memaddr & 0xFF);
|
|
uint8_t * p = obj;
|
|
for (uint8_t i = 0; i < size; i++)
|
|
{
|
|
_wire->write(*p++);
|
|
}
|
|
_wire->endTransmission();
|
|
}
|
|
|
|
|
|
void FRAM::readBlock(uint16_t memaddr, uint8_t * obj, uint8_t size)
|
|
{
|
|
_wire->beginTransmission(_address);
|
|
_wire->write(memaddr >> 8);
|
|
_wire->write(memaddr & 0xFF);
|
|
_wire->endTransmission();
|
|
_wire->requestFrom(_address, size);
|
|
uint8_t * p = obj;
|
|
for (uint8_t i = 0; i < size; i++)
|
|
{
|
|
*p++ = _wire->read();
|
|
}
|
|
}
|
|
|
|
// -- END OF FILE --
|