Skip to content

Add i2cee-driver to components #10711

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

Merged
merged 22 commits into from
Aug 30, 2019
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
26 changes: 26 additions & 0 deletions components/storage/blockdevice/COMPONENT_I2CEE/.travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
dist: xenial
language: python
python: 2.7

install:
# Get arm-none-eabi-gcc
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
- sudo apt-get update -qq
- sudo apt-get install -qq gcc-arm-embedded
# Get dependencies
- git clone https://github.com/armmbed/mbed-os.git
# Install python dependencies
# - python -m pip install --upgrade pip==18.1
# - python -m pip install --upgrade setuptools==40.4.3
- pip install -r mbed-os/requirements.txt

script:
# Check that examples compile
- sed -n '/``` cpp/,${/```$/q;/```/d;p}' README.md > main.cpp &&
PYTHONPATH=mbed-os python mbed-os/tools/make.py -t GCC_ARM -m K82F
--source=. --build=BUILD/K82F/GCC_ARM -j0 &&
rm main.cpp
- sed -n '/@code/,${/@endcode/q;/@/d;s/^ \*//;p}' I2CEEBlockDevice.h > main.cpp &&
PYTHONPATH=mbed-os python mbed-os/tools/make.py -t GCC_ARM -m K82F
--source=. --build=BUILD/K82F/GCC_ARM -j0 &&
rm main.cpp
161 changes: 161 additions & 0 deletions components/storage/blockdevice/COMPONENT_I2CEE/I2CEEBlockDevice.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/* Simple access class for I2C EEPROM chips like Microchip 24LC
* Copyright (c) 2015 Robin Hourahane
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "I2CEEBlockDevice.h"
#include "rtos/ThisThread.h"
using namespace mbed;

#define I2CEE_TIMEOUT 10000


I2CEEBlockDevice::I2CEEBlockDevice(
PinName sda, PinName scl, uint8_t addr,
bd_size_t size, bd_size_t block, int freq)
: _i2c_addr(addr), _size(size), _block(block)
{
_i2c = new (_i2c_buffer) I2C(sda, scl);
_i2c->frequency(freq);
}

I2CEEBlockDevice::I2CEEBlockDevice(
I2C *i2c_obj, uint8_t addr,
bd_size_t size, bd_size_t block)
: _i2c_addr(addr), _size(size), _block(block)
{
_i2c = i2c_obj;
}
I2CEEBlockDevice::~I2CEEBlockDevice()
{
if (_i2c == (I2C *)_i2c_buffer) {
_i2c->~I2C();
}
}

int I2CEEBlockDevice::init()
{
return _sync();
}

int I2CEEBlockDevice::deinit()
{
return 0;
}

int I2CEEBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
{
// Check the address and size fit onto the chip.
MBED_ASSERT(is_valid_read(addr, size));

_i2c->start();

if (!_i2c->write(_i2c_addr | 0) ||
!_i2c->write((char)(addr >> 8)) ||
!_i2c->write((char)(addr & 0xff))) {
return BD_ERROR_DEVICE_ERROR;
}

_i2c->stop();

if (_i2c->read(_i2c_addr, static_cast<char *>(buffer), size) < 0) {
return BD_ERROR_DEVICE_ERROR;
}

return 0;
}

int I2CEEBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
{
// Check the addr and size fit onto the chip.
MBED_ASSERT(is_valid_program(addr, size));

// While we have some more data to write.
while (size > 0) {
uint32_t off = addr % _block;
uint32_t chunk = (off + size < _block) ? size : (_block - off);

_i2c->start();

if (!_i2c->write(_i2c_addr | 0) ||
!_i2c->write((char)(addr >> 8)) ||
!_i2c->write((char)(addr & 0xff))) {
return BD_ERROR_DEVICE_ERROR;
}

for (unsigned i = 0; i < chunk; i++) {
_i2c->write(static_cast<const char *>(buffer)[i]);
}

_i2c->stop();

int err = _sync();

if (err) {
return err;
}

addr += chunk;
size -= chunk;
buffer = static_cast<const char *>(buffer) + chunk;
}

return 0;
}

int I2CEEBlockDevice::erase(bd_addr_t addr, bd_size_t size)
{
// No erase needed
return 0;
}

int I2CEEBlockDevice::_sync()
{
// The chip doesn't ACK while writing to the actual EEPROM
// so loop trying to do a zero byte write until it is ACKed
// by the chip.
for (int i = 0; i < I2CEE_TIMEOUT; i++) {
if (_i2c->write(_i2c_addr | 0, 0, 0) < 1) {
return 0;
}

rtos::ThisThread::sleep_for(1);
}

return BD_ERROR_DEVICE_ERROR;
}

bd_size_t I2CEEBlockDevice::get_read_size() const
{
return 1;
}

bd_size_t I2CEEBlockDevice::get_program_size() const
{
return 1;
}

bd_size_t I2CEEBlockDevice::get_erase_size() const
{
return 1;
}

bd_size_t I2CEEBlockDevice::size() const
{
return _size;
}

const char *I2CEEBlockDevice::get_type() const
{
return "I2CEE";
}
176 changes: 176 additions & 0 deletions components/storage/blockdevice/COMPONENT_I2CEE/I2CEEBlockDevice.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/* Simple access class for I2C EEPROM chips like Microchip 24LC
* Copyright (c) 2015 Robin Hourahane
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_I2CEEPROM_BLOCK_DEVICE_H
#define MBED_I2CEEPROM_BLOCK_DEVICE_H

#include "BlockDevice.h"
#include "I2C.h"

/** BlockDevice for I2C based flash device such as
* Microchip's 24LC or ATMEL's AT24C ranges
*
* @code
* // Here's an example using a 24LC256 on a GR PEACH
* #include "mbed.h"
* #include "I2CEEBlockDevice.h"
*
* // Create EEPROM device on I2C bus with 32kbytes of memory
* I2CEEBlockDevice i2cee(D14, D15, 0xa0, 32*1024);
*
* int main() {
* printf("i2cee test\n");
*
* // Initialize the device and print the memory layout
* i2cee.init();
* printf("i2cee size: %llu\n", i2cee.size());
* printf("i2cee read size: %llu\n", i2cee.get_read_size());
* printf("i2cee program size: %llu\n", i2cee.get_program_size());
* printf("i2cee erase size: %llu\n", i2cee.get_erase_size());
*
* // Write "Hello World!" to the first block
* char *buffer = (char*)malloc(i2cee.get_erase_size());
* sprintf(buffer, "Hello World!\n");
* i2cee.erase(0, i2cee.get_erase_size());
* i2cee.program(buffer, 0, i2cee.get_erase_size());
*
* // Read back what was stored
* i2cee.read(buffer, 0, i2cee.get_erase_size());
* printf("%s", buffer);
*
* // Deinitialize the device
* i2cee.deinit();
* }
* @endcode
*/
class I2CEEBlockDevice : public BlockDevice {
public:
/** Constructor to create an I2CEEBlockDevice on I2C pins
*
* @param sda The pin name for the sda line of the I2C bus.
* @param scl The pin name for the scl line of the I2C bus.
* @param addr The 8bit I2C address of the chip, common range 0xa0 - 0xae.
* @param size The size of the device in bytes
* @param block The page size of the device in bytes, defaults to 32bytes
* @param freq The frequency of the I2C bus, defaults to 400K.
*/
I2CEEBlockDevice(
PinName sda, PinName scl, uint8_t address,
bd_size_t size, bd_size_t block = 32,
int bus_speed = 400000);

/** Constructor to create an I2CEEBlockDevice on I2C pins
*
* @param i2c The I2C instance pointer
* @param addr The 8bit I2C address of the chip, common range 0xa0 - 0xae.
* @param size The size of the device in bytes
* @param block The page size of the device in bytes, defaults to 32bytes
* @param freq The frequency of the I2C bus, defaults to 400K.
*/
I2CEEBlockDevice(
mbed::I2C *i2c_obj, uint8_t address,
bd_size_t size, bd_size_t block = 32);

/** Destructor of I2CEEBlockDevice
*/

virtual ~I2CEEBlockDevice();

/** Initialize a block device
*
* @return 0 on success or a negative error code on failure
*/
virtual int init();

/** Deinitialize a block device
*
* @return 0 on success or a negative error code on failure
*/
virtual int deinit();

/** Read blocks from a block device
*
* @param buffer Buffer to write blocks to
* @param addr Address of block to begin reading from
* @param size Size to read in bytes, must be a multiple of read block size
* @return 0 on success, negative error code on failure
*/
virtual int read(void *buffer, bd_addr_t addr, bd_size_t size);

/** Program blocks to a block device
*
* The blocks must have been erased prior to being programmed
*
* @param buffer Buffer of data to write to blocks
* @param addr Address of block to begin writing to
* @param size Size to write in bytes, must be a multiple of program block size
* @return 0 on success, negative error code on failure
*/
virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);

/** Erase blocks on a block device
*
* The state of an erased block is undefined until it has been programmed
*
* @param addr Address of block to begin erasing
* @param size Size to erase in bytes, must be a multiple of erase block size
* @return 0 on success, negative error code on failure
*/
virtual int erase(bd_addr_t addr, bd_size_t size);

/** Get the size of a readable block
*
* @return Size of a readable block in bytes
*/
virtual bd_size_t get_read_size() const;

/** Get the size of a programable block
*
* @return Size of a programable block in bytes
* @note Must be a multiple of the read size
*/
virtual bd_size_t get_program_size() const;

/** Get the size of a eraseable block
*
* @return Size of a eraseable block in bytes
* @note Must be a multiple of the program size
*/
virtual bd_size_t get_erase_size() const;

/** Get the total size of the underlying device
*
* @return Size of the underlying device in bytes
*/
virtual bd_size_t size() const;

/** Get the BlockDevice class type.
*
* @return A string representation of the BlockDevice class type.
*/
virtual const char *get_type() const;

private:
mbed::I2C *_i2c;
uint32_t _i2c_buffer[sizeof(mbed::I2C) / sizeof(uint32_t)];
uint8_t _i2c_addr;
uint32_t _size;
uint32_t _block;

int _sync();
};


#endif /* MBED_SD_BLOCK_DEVICE_H */
Loading