Add Eight-Bit-Adressing mode to I2CEEBlockDevice.

When dealing with EEPROMs without a 16 bit adressing, the current
implementation does not work, as it writes a 16 bit address to the chip.
This may cause undefined behaviour.
This change adds a new constructor argument to enable this new eight-bit
mode. It defaults to false to not break existing code.
This constructor argument should actually never be necessary to manually
set, except when dealing with cheap devices.
pull/12446/head
Stephan Brunner 2020-02-16 12:47:20 +01:00
parent 3d038e55ee
commit cd34860bd0
2 changed files with 51 additions and 25 deletions

View File

@ -22,8 +22,10 @@ using namespace mbed;
I2CEEBlockDevice::I2CEEBlockDevice( I2CEEBlockDevice::I2CEEBlockDevice(
PinName sda, PinName scl, uint8_t addr, PinName sda, PinName scl, uint8_t addr,
bd_size_t size, bd_size_t block, int freq) bd_size_t size, bd_size_t block, int freq,
: _i2c_addr(addr), _size(size), _block(block) bool address_is_eight_bit)
: _i2c_addr(addr), _size(size), _block(block),
_address_is_eight_bit(address_is_eight_bit)
{ {
_i2c = new (_i2c_buffer) I2C(sda, scl); _i2c = new (_i2c_buffer) I2C(sda, scl);
_i2c->frequency(freq); _i2c->frequency(freq);
@ -31,8 +33,10 @@ I2CEEBlockDevice::I2CEEBlockDevice(
I2CEEBlockDevice::I2CEEBlockDevice( I2CEEBlockDevice::I2CEEBlockDevice(
I2C *i2c_obj, uint8_t addr, I2C *i2c_obj, uint8_t addr,
bd_size_t size, bd_size_t block) bd_size_t size, bd_size_t block,
: _i2c_addr(addr), _size(size), _block(block) bool address_is_eight_bit)
: _i2c_addr(addr), _size(size), _block(block),
_address_is_eight_bit(address_is_eight_bit)
{ {
_i2c = i2c_obj; _i2c = i2c_obj;
} }
@ -60,9 +64,15 @@ int I2CEEBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
_i2c->start(); _i2c->start();
if (!_i2c->write(_i2c_addr | 0) || if (!_i2c->write(_i2c_addr | 0)) {
!_i2c->write((char)(addr >> 8)) || return BD_ERROR_DEVICE_ERROR;
!_i2c->write((char)(addr & 0xff))) { }
if (!_address_is_eight_bit && !_i2c->write((char)(addr >> 8))) {
return BD_ERROR_DEVICE_ERROR;
}
if (!_i2c->write((char)(addr & 0xff))) {
return BD_ERROR_DEVICE_ERROR; return BD_ERROR_DEVICE_ERROR;
} }
@ -92,9 +102,15 @@ int I2CEEBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size
_i2c->start(); _i2c->start();
if (!_i2c->write(_i2c_addr | 0) || if (!_i2c->write(_i2c_addr | 0)) {
!_i2c->write((char)(addr >> 8)) || return BD_ERROR_DEVICE_ERROR;
!_i2c->write((char)(addr & 0xff))) { }
if (!_address_is_eight_bit && !_i2c->write((char)(addr >> 8))) {
return BD_ERROR_DEVICE_ERROR;
}
if (!_i2c->write((char)(addr & 0xff))) {
return BD_ERROR_DEVICE_ERROR; return BD_ERROR_DEVICE_ERROR;
} }

View File

@ -65,11 +65,15 @@ public:
* @param size The size of the device in bytes * @param size The size of the device in bytes
* @param block The page size of the device in bytes, defaults to 32bytes * @param block The page size of the device in bytes, defaults to 32bytes
* @param freq The frequency of the I2C bus, defaults to 400K. * @param freq The frequency of the I2C bus, defaults to 400K.
* @param address_is_eight_bit Specifies whether the EEPROM device is using eight bit
* addresses instead of 16 bit addresses. This should not be needed
* unless dealing with very cheap devices.
*/ */
I2CEEBlockDevice( I2CEEBlockDevice(
PinName sda, PinName scl, uint8_t address, PinName sda, PinName scl, uint8_t address,
bd_size_t size, bd_size_t block = 32, bd_size_t size, bd_size_t block = 32,
int bus_speed = 400000); int bus_speed = 400000,
bool address_is_eight_bit = false);
/** Constructor to create an I2CEEBlockDevice on I2C pins /** Constructor to create an I2CEEBlockDevice on I2C pins
* *
@ -78,10 +82,14 @@ public:
* @param size The size of the device in bytes * @param size The size of the device in bytes
* @param block The page size of the device in bytes, defaults to 32bytes * @param block The page size of the device in bytes, defaults to 32bytes
* @param freq The frequency of the I2C bus, defaults to 400K. * @param freq The frequency of the I2C bus, defaults to 400K.
* @param address_is_eight_bit Specifies whether the EEPROM device is using eight bit
* addresses instead of 16 bit addresses. This should not be needed
* unless dealing with very cheap devices.
*/ */
I2CEEBlockDevice( I2CEEBlockDevice(
mbed::I2C *i2c_obj, uint8_t address, mbed::I2C *i2c_obj, uint8_t address,
bd_size_t size, bd_size_t block = 32); bd_size_t size, bd_size_t block = 32,
bool address_is_eight_bit = false);
/** Destructor of I2CEEBlockDevice /** Destructor of I2CEEBlockDevice
*/ */
@ -169,6 +177,8 @@ private:
uint32_t _size; uint32_t _size;
uint32_t _block; uint32_t _block;
bool _address_is_eight_bit;
int _sync(); int _sync();
}; };