Skip to content

Commit a18259a

Browse files
authored
Merge pull request #12446 from boomer41/i2cee-add-eight-bit-address
Add Eight-Bit-Addressing mode to I2CEEBlockDevice.
2 parents c520449 + 440fa49 commit a18259a

File tree

2 files changed

+82
-34
lines changed

2 files changed

+82
-34
lines changed

components/storage/blockdevice/COMPONENT_I2CEE/I2CEEBlockDevice.cpp

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,21 @@ using namespace mbed;
2222

2323
I2CEEBlockDevice::I2CEEBlockDevice(
2424
PinName sda, PinName scl, uint8_t addr,
25-
bd_size_t size, bd_size_t block, int freq)
26-
: _i2c_addr(addr), _size(size), _block(block)
25+
bd_size_t size, bd_size_t block, int freq,
26+
bool address_is_eight_bit)
27+
: _i2c_addr(addr), _size(size), _block(block),
28+
_address_is_eight_bit(address_is_eight_bit)
2729
{
2830
_i2c = new (_i2c_buffer) I2C(sda, scl);
2931
_i2c->frequency(freq);
3032
}
3133

3234
I2CEEBlockDevice::I2CEEBlockDevice(
3335
I2C *i2c_obj, uint8_t addr,
34-
bd_size_t size, bd_size_t block)
35-
: _i2c_addr(addr), _size(size), _block(block)
36+
bd_size_t size, bd_size_t block,
37+
bool address_is_eight_bit)
38+
: _i2c_addr(addr), _size(size), _block(block),
39+
_address_is_eight_bit(address_is_eight_bit)
3640
{
3741
_i2c = i2c_obj;
3842
}
@@ -58,48 +62,61 @@ int I2CEEBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
5862
// Check the address and size fit onto the chip.
5963
MBED_ASSERT(is_valid_read(addr, size));
6064

65+
auto *pBuffer = static_cast<char *>(buffer);
66+
6167
_i2c->start();
6268

63-
if (!_i2c->write(_i2c_addr | 0) ||
64-
!_i2c->write((char)(addr >> 8)) ||
65-
!_i2c->write((char)(addr & 0xff))) {
69+
if (1 != _i2c->write(get_paged_device_address(addr))) {
6670
return BD_ERROR_DEVICE_ERROR;
6771
}
6872

69-
_i2c->stop();
73+
if (!_address_is_eight_bit && 1 != _i2c->write((char)(addr >> 8u))) {
74+
return BD_ERROR_DEVICE_ERROR;
75+
}
7076

71-
auto err = _sync();
72-
if (err) {
73-
return err;
77+
if (1 != _i2c->write((char)(addr & 0xffu))) {
78+
return BD_ERROR_DEVICE_ERROR;
7479
}
7580

76-
if (0 != _i2c->read(_i2c_addr, static_cast<char *>(buffer), size)) {
81+
_i2c->stop();
82+
83+
if (0 != _i2c->read(_i2c_addr, pBuffer, size)) {
7784
return BD_ERROR_DEVICE_ERROR;
7885
}
7986

80-
return 0;
87+
return BD_ERROR_OK;
8188
}
8289

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

95+
const auto *pBuffer = static_cast<const char *>(buffer);
96+
8897
// While we have some more data to write.
8998
while (size > 0) {
9099
uint32_t off = addr % _block;
91100
uint32_t chunk = (off + size < _block) ? size : (_block - off);
92101

93102
_i2c->start();
94103

95-
if (!_i2c->write(_i2c_addr | 0) ||
96-
!_i2c->write((char)(addr >> 8)) ||
97-
!_i2c->write((char)(addr & 0xff))) {
104+
if (1 != _i2c->write(get_paged_device_address(addr))) {
105+
return BD_ERROR_DEVICE_ERROR;
106+
}
107+
108+
if (!_address_is_eight_bit && 1 != _i2c->write((char)(addr >> 8u))) {
109+
return BD_ERROR_DEVICE_ERROR;
110+
}
111+
112+
if (1 != _i2c->write((char)(addr & 0xffu))) {
98113
return BD_ERROR_DEVICE_ERROR;
99114
}
100115

101116
for (unsigned i = 0; i < chunk; i++) {
102-
_i2c->write(static_cast<const char *>(buffer)[i]);
117+
if (1 != _i2c->write(pBuffer[i])) {
118+
return BD_ERROR_DEVICE_ERROR;
119+
}
103120
}
104121

105122
_i2c->stop();
@@ -112,10 +129,10 @@ int I2CEEBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size
112129

113130
addr += chunk;
114131
size -= chunk;
115-
buffer = static_cast<const char *>(buffer) + chunk;
132+
pBuffer += chunk;
116133
}
117134

118-
return 0;
135+
return BD_ERROR_OK;
119136
}
120137

121138
int I2CEEBlockDevice::erase(bd_addr_t addr, bd_size_t size)
@@ -164,3 +181,15 @@ const char *I2CEEBlockDevice::get_type() const
164181
{
165182
return "I2CEE";
166183
}
184+
185+
uint8_t I2CEEBlockDevice::get_paged_device_address(bd_addr_t address)
186+
{
187+
if (!_address_is_eight_bit) {
188+
return _i2c_addr;
189+
} else {
190+
// Use the three least significant bits of the 2nd byte as the page
191+
// The page will be bits 2-4 of the user defined addresses.
192+
return _i2c_addr | ((address & 0x0700u) >> 7u);
193+
}
194+
}
195+

components/storage/blockdevice/COMPONENT_I2CEE/I2CEEBlockDevice.h

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,29 +59,37 @@ class I2CEEBlockDevice : public BlockDevice {
5959
public:
6060
/** Constructor to create an I2CEEBlockDevice on I2C pins
6161
*
62-
* @param sda The pin name for the sda line of the I2C bus.
63-
* @param scl The pin name for the scl line of the I2C bus.
64-
* @param addr The 8bit I2C address of the chip, common range 0xa0 - 0xae.
65-
* @param size The size of the device in bytes
66-
* @param block The page size of the device in bytes, defaults to 32bytes
67-
* @param freq The frequency of the I2C bus, defaults to 400K.
62+
* @param sda The pin name for the sda line of the I2C bus.
63+
* @param scl The pin name for the scl line of the I2C bus.
64+
* @param addr The 8bit I2C address of the chip, common range 0xa0 - 0xae.
65+
* @param size The size of the device in bytes
66+
* @param block The page size of the device in bytes, defaults to 32bytes
67+
* @param freq The frequency of the I2C bus, defaults to 400K.
68+
* @param address_is_eight_bit Specifies whether the EEPROM device is using eight bit
69+
* addresses instead of 16 bit addresses. This is used for example
70+
* in AT24C series chips.
6871
*/
6972
I2CEEBlockDevice(
7073
PinName sda, PinName scl, uint8_t address,
7174
bd_size_t size, bd_size_t block = 32,
72-
int bus_speed = 400000);
75+
int bus_speed = 400000,
76+
bool address_is_eight_bit = false);
7377

7478
/** Constructor to create an I2CEEBlockDevice on I2C pins
75-
*
76-
* @param i2c The I2C instance pointer
77-
* @param addr The 8bit I2C address of the chip, common range 0xa0 - 0xae.
78-
* @param size The size of the device in bytes
79-
* @param block The page size of the device in bytes, defaults to 32bytes
80-
* @param freq The frequency of the I2C bus, defaults to 400K.
81-
*/
79+
*
80+
* @param i2c The I2C instance pointer
81+
* @param addr The 8bit I2C address of the chip, common range 0xa0 - 0xae.
82+
* @param size The size of the device in bytes
83+
* @param block The page size of the device in bytes, defaults to 32bytes
84+
* @param freq The frequency of the I2C bus, defaults to 400K.
85+
* @param address_is_eight_bit Specifies whether the EEPROM device is using eight bit
86+
* addresses instead of 16 bit addresses. This is used for example
87+
* in AT24C series chips.
88+
*/
8289
I2CEEBlockDevice(
8390
mbed::I2C *i2c_obj, uint8_t address,
84-
bd_size_t size, bd_size_t block = 32);
91+
bd_size_t size, bd_size_t block = 32,
92+
bool address_is_eight_bit = false);
8593

8694
/** Destructor of I2CEEBlockDevice
8795
*/
@@ -166,10 +174,21 @@ class I2CEEBlockDevice : public BlockDevice {
166174
mbed::I2C *_i2c;
167175
uint32_t _i2c_buffer[sizeof(mbed::I2C) / sizeof(uint32_t)];
168176
uint8_t _i2c_addr;
177+
bool _address_is_eight_bit;
169178
uint32_t _size;
170179
uint32_t _block;
171180

172181
int _sync();
182+
183+
/**
184+
* Gets the device's I2C address with respect to the requested page.
185+
* When eight-bit mode is disabled, this function is a noop.
186+
* When eight-bit mode is enabled, it sets the bits required
187+
* in the devices address. Other bits remain unchanged.
188+
* @param address An address in the requested page.
189+
* @return The device's I2C address for that page
190+
*/
191+
uint8_t get_paged_device_address(bd_addr_t address);
173192
};
174193

175194

0 commit comments

Comments
 (0)