Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added Fujitsu MB85RS4MT FRAM; added sleep mode #31

Merged
merged 3 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions .github/workflows/githubci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ on: [pull_request, push, repository_dispatch]
jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/setup-python@v4
with:
python-version: '3.x'
- uses: actions/checkout@v3
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Run pre-commit
uses: pre-commit/[email protected]

- uses: actions/checkout@v4
with:
repository: adafruit/ci-arduino
path: ci
Expand All @@ -22,9 +22,6 @@ jobs:
- name: test platforms
run: python3 ci/build_platform.py main_platforms

- name: clang
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .

- name: doxygen
env:
GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }}
Expand Down
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
#
# SPDX-License-Identifier: Unlicense

repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v15.0.7
hooks:
- id: clang-format
types_or: [c++, c, header]
160 changes: 110 additions & 50 deletions Adafruit_FRAM_SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,39 @@
* @section license License
*
* BSD license, all text above must be included in any redistribution
*
* History
* - FUEL4EP: Added sleep mode support
*/

#include <math.h>
#include <stdlib.h>

#include "Adafruit_FRAM_SPI.h"

/// Supported flash devices
const struct {
uint8_t manufID; ///< Manufacture ID
uint16_t prodID; ///< Product ID
uint32_t size; ///< Size in bytes
uint8_t manufID; ///< Manufacture ID
uint16_t prodID; ///< Product ID
uint32_t size; ///< Size in bytes
bool support_sleep; ///< Support sleep mode
} _supported_devices[] = {
// Sorted in numerical order
// Fujitsu
{0x04, 0x0101, 2 * 1024UL}, // MB85RS16
{0x04, 0x0302, 8 * 1024UL}, // MB85RS64V
{0x04, 0x2303, 8 * 1024UL}, // MB85RS64T
{0x04, 0x2503, 32 * 1024UL}, // MB85RS256TY
{0x04, 0x2703, 128 * 1024UL}, // MB85RS1MT
{0x04, 0x4803, 256 * 1024UL}, // MB85RS2MTA
{0x04, 0x4903, 512 * 1024UL}, // MB85RS4MT
{0x04, 0x0101, 2 * 1024UL, false}, // MB85RS16
{0x04, 0x0302, 8 * 1024UL, false}, // MB85RS64V
{0x04, 0x2303, 8 * 1024UL, true}, // MB85RS64T
{0x04, 0x2503, 32 * 1024UL, true}, // MB85RS256TY
{0x04, 0x2703, 128 * 1024UL, true}, // MB85RS1MT
{0x04, 0x4803, 256 * 1024UL, true}, // MB85RS2MTA
{0x04, 0x2803, 256 * 1024UL, true}, // MB85RS2MT
{0x04, 0x4903, 512 * 1024UL, true}, // MB85RS4MT

// Cypress
{0x7F, 0x7F7f, 32 * 1024UL}, // FM25V02
// (manu = 7F7F7F7F7F7FC2, device = 0x2200)
{0x7F, 0x7F7f, 32 * 1024UL, false}, // FM25V02
// (manu = 7F7F7F7F7F7FC2, device = 0x2200)

// Lapis
{0xAE, 0x8305, 8 * 1024UL} // MR45V064B
{0xAE, 0x8305, 8 * 1024UL, false} // MR45V064B
};

/*!
Expand All @@ -62,22 +66,25 @@ const struct {
* ManufactureID to be checked
* @param prodID
* ProductID to be checked
* @return size of device, 0 if not supported
* @return device index, -1 if not supported
*/
static uint32_t check_supported_device(uint8_t manufID, uint16_t prodID) {
for (uint8_t i = 0;
static int get_supported_idx(uint8_t manufID, uint16_t prodID) {
for (int i = 0;
i < sizeof(_supported_devices) / sizeof(_supported_devices[0]); i++) {
if (manufID == _supported_devices[i].manufID &&
prodID == _supported_devices[i].prodID)
return _supported_devices[i].size;
return i;
}

Serial.print(F("Unexpected Device: Manufacturer ID = 0x"));
Serial.print(manufID, HEX);
Serial.print(F(", Product ID = 0x"));
Serial.println(prodID, HEX);
return -1;
}

return 0;
/*!
* @brief Initialize the SPI FRAM class
*/
void Adafruit_FRAM_SPI::init(void) {
_nAddressSizeBytes = 0;
_dev_idx = -1;
}

/*!
Expand All @@ -91,10 +98,7 @@ static uint32_t check_supported_device(uint8_t manufID, uint16_t prodID) {
*/
Adafruit_FRAM_SPI::Adafruit_FRAM_SPI(int8_t cs, SPIClass *theSPI,
uint32_t freq) {
if (spi_dev) {
delete spi_dev;
}

init();
spi_dev = new Adafruit_SPIDevice(cs, freq, SPI_BITORDER_MSBFIRST, SPI_MODE0,
theSPI);
}
Expand All @@ -112,12 +116,15 @@ Adafruit_FRAM_SPI::Adafruit_FRAM_SPI(int8_t cs, SPIClass *theSPI,
*/
Adafruit_FRAM_SPI::Adafruit_FRAM_SPI(int8_t clk, int8_t miso, int8_t mosi,
int8_t cs) {
init();
spi_dev = new Adafruit_SPIDevice(cs, clk, miso, mosi, 1000000,
SPI_BITORDER_MSBFIRST, SPI_MODE0);
}

Adafruit_FRAM_SPI::~Adafruit_FRAM_SPI(void) {
if (spi_dev) {
delete spi_dev;
}

spi_dev = new Adafruit_SPIDevice(cs, clk, miso, mosi, 1000000,
SPI_BITORDER_MSBFIRST, SPI_MODE0);
}

/*!
Expand All @@ -128,8 +135,8 @@ Adafruit_FRAM_SPI::Adafruit_FRAM_SPI(int8_t clk, int8_t miso, int8_t mosi,
* @return true if successful
*/
bool Adafruit_FRAM_SPI::begin(uint8_t nAddressSizeBytes) {
(void)
nAddressSizeBytes; // not used anymore, since we will use auto-detect size
// not used anymore, since we will use auto-detect size
(void)nAddressSizeBytes;

/* Configure SPI */
if (!spi_dev->begin()) {
Expand All @@ -142,19 +149,29 @@ bool Adafruit_FRAM_SPI::begin(uint8_t nAddressSizeBytes) {
getDeviceID(&manufID, &prodID);

/* Everything seems to be properly initialised and connected */
uint32_t fram_size = check_supported_device(manufID, prodID);

Serial.print(F("FRAM Size = 0x"));
Serial.println(fram_size, HEX);
_dev_idx = get_supported_idx(manufID, prodID);

// Detect address size in bytes either 2 or 3 bytes (4 bytes is not supported)
if (fram_size > 64UL * 1024) {
setAddressSize(3);
if (_dev_idx == -1) {
Serial.print(F("Unexpected Device: Manufacturer ID = 0x"));
Serial.print(manufID, HEX);
Serial.print(F(", Product ID = 0x"));
Serial.println(prodID, HEX);
return false;
} else {
setAddressSize(2);
uint32_t fram_size = _supported_devices[_dev_idx].size;
Serial.print(F("FRAM Size = 0x"));
Serial.println(fram_size, HEX);

// Detect address size in bytes either 2 or 3 bytes (4 bytes is not
// supported)
if (fram_size > 64UL * 1024) {
setAddressSize(3);
} else {
setAddressSize(2);
}

return true;
}

return fram_size != 0;
}

/*!
Expand Down Expand Up @@ -187,10 +204,12 @@ bool Adafruit_FRAM_SPI::write8(uint32_t addr, uint8_t value) {
uint8_t i = 0;

buffer[i++] = OPCODE_WRITE;
if (_nAddressSizeBytes > 3)
if (_nAddressSizeBytes > 3) {
buffer[i++] = (uint8_t)(addr >> 24);
if (_nAddressSizeBytes > 2)
}
if (_nAddressSizeBytes > 2) {
buffer[i++] = (uint8_t)(addr >> 16);
}
buffer[i++] = (uint8_t)(addr >> 8);
buffer[i++] = (uint8_t)(addr & 0xFF);
buffer[i++] = value;
Expand All @@ -214,10 +233,12 @@ bool Adafruit_FRAM_SPI::write(uint32_t addr, const uint8_t *values,
uint8_t i = 0;

prebuf[i++] = OPCODE_WRITE;
if (_nAddressSizeBytes > 3)
if (_nAddressSizeBytes > 3) {
prebuf[i++] = (uint8_t)(addr >> 24);
if (_nAddressSizeBytes > 2)
}
if (_nAddressSizeBytes > 2) {
prebuf[i++] = (uint8_t)(addr >> 16);
}
prebuf[i++] = (uint8_t)(addr >> 8);
prebuf[i++] = (uint8_t)(addr & 0xFF);

Expand All @@ -235,10 +256,12 @@ uint8_t Adafruit_FRAM_SPI::read8(uint32_t addr) {
uint8_t i = 0;

buffer[i++] = OPCODE_READ;
if (_nAddressSizeBytes > 3)
if (_nAddressSizeBytes > 3) {
buffer[i++] = (uint8_t)(addr >> 24);
if (_nAddressSizeBytes > 2)
}
if (_nAddressSizeBytes > 2) {
buffer[i++] = (uint8_t)(addr >> 16);
}
buffer[i++] = (uint8_t)(addr >> 8);
buffer[i++] = (uint8_t)(addr & 0xFF);

Expand All @@ -262,10 +285,12 @@ bool Adafruit_FRAM_SPI::read(uint32_t addr, uint8_t *values, size_t count) {
uint8_t i = 0;

buffer[i++] = OPCODE_READ;
if (_nAddressSizeBytes > 3)
if (_nAddressSizeBytes > 3) {
buffer[i++] = (uint8_t)(addr >> 24);
if (_nAddressSizeBytes > 2)
}
if (_nAddressSizeBytes > 2) {
buffer[i++] = (uint8_t)(addr >> 16);
}
buffer[i++] = (uint8_t)(addr >> 8);
buffer[i++] = (uint8_t)(addr & 0xFF);

Expand Down Expand Up @@ -343,3 +368,38 @@ bool Adafruit_FRAM_SPI::setStatusRegister(uint8_t value) {
void Adafruit_FRAM_SPI::setAddressSize(uint8_t nAddressSize) {
_nAddressSizeBytes = nAddressSize;
}

/*!
* @brief Enters the FRAM's low power sleep mode
* @return true if successful
*/
// WARNING: this method has not yet been validated
bool Adafruit_FRAM_SPI::enterSleep(void) {
if (_dev_idx == -1 || !_supported_devices[_dev_idx].support_sleep) {
return false;
}
uint8_t cmd = OPCODE_SLEEP;
return spi_dev->write(&cmd, 1);
}

/*!
* @brief exits the FRAM's low power sleep mode
* @return true if successful
*/
// WARNING: this method has not yet been validated
bool Adafruit_FRAM_SPI::exitSleep(void) {
if (_dev_idx == -1 || !_supported_devices[_dev_idx].support_sleep) {
return false;
}

// Returning to a normal operation from the SLEEP mode is carried out after
// tREC (Max 400 μs) time from the falling edge of CS
spi_dev->beginTransactionWithAssertingCS();
delayMicroseconds(300);
// It is possible to return CS to H level before tREC time. However, it
// is prohibited to bring down CS to L level again during tREC period.
spi_dev->endTransactionWithDeassertingCS();
delayMicroseconds(100);

return true;
}
23 changes: 15 additions & 8 deletions Adafruit_FRAM_SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*
* BSD license, all text above must be included in any redistribution
*/

#ifndef _ADAFRUIT_FRAM_SPI_H_
#define _ADAFRUIT_FRAM_SPI_H_

Expand All @@ -27,13 +28,14 @@

/** Operation Codes **/
typedef enum opcodes_e {
OPCODE_WREN = 0b0110, /* Write Enable Latch */
OPCODE_WRDI = 0b0100, /* Reset Write Enable Latch */
OPCODE_RDSR = 0b0101, /* Read Status Register */
OPCODE_WRSR = 0b0001, /* Write Status Register */
OPCODE_READ = 0b0011, /* Read Memory */
OPCODE_WRITE = 0b0010, /* Write Memory */
OPCODE_RDID = 0b10011111 /* Read Device ID */
OPCODE_WREN = 0b0110, /* Write Enable Latch */
OPCODE_WRDI = 0b0100, /* Reset Write Enable Latch */
OPCODE_RDSR = 0b0101, /* Read Status Register */
OPCODE_WRSR = 0b0001, /* Write Status Register */
OPCODE_READ = 0b0011, /* Read Memory */
OPCODE_WRITE = 0b0010, /* Write Memory */
OPCODE_RDID = 0b10011111, /* Read Device ID */
OPCODE_SLEEP = 0b10111001 /* Sleep Mode */
} opcodes_t;

/*!
Expand All @@ -45,6 +47,7 @@ class Adafruit_FRAM_SPI {
Adafruit_FRAM_SPI(int8_t cs, SPIClass *theSPI = &SPI,
uint32_t freq = 1000000);
Adafruit_FRAM_SPI(int8_t clk, int8_t miso, int8_t mosi, int8_t cs);
virtual ~Adafruit_FRAM_SPI(void);

bool begin(uint8_t nAddressSizeBytes = 2);
bool writeEnable(bool enable);
Expand All @@ -56,10 +59,14 @@ class Adafruit_FRAM_SPI {
uint8_t getStatusRegister(void);
bool setStatusRegister(uint8_t value);
void setAddressSize(uint8_t nAddressSize);
bool enterSleep(void);
bool exitSleep(void);

private:
Adafruit_SPIDevice *spi_dev = NULL;
void init(void);
Adafruit_SPIDevice *spi_dev;
uint8_t _nAddressSizeBytes;
int _dev_idx;
};

#endif
Loading