Martyn Gilbertson / M24512

M24512.cpp

Committer:
Martyn Gilbertson
Date:
2019-06-07
Revision:
0:11e6262c2981
Child:
3:b6d7714cd171

File content as of revision 0:11e6262c2981:

/* ISL MBED Libraries
 * Copyright (C) 2019 - Invisible Systems Ltd. All Rights Reserved.
 */
#include "M24512.h"


/** I2C Frequency
     Roughly calculate time to write a full page based on freq
	 ((1 / 500000) * (130*9) * 1000) + 5
*/
#define M24512_DEFAULT_FREQUENCY (uint32_t)500000

/** Read command | on device address
*/
#define M24512_COMMAND_READ     (uint8_t)0

/** Write command | on device address
*/
#define M24512_COMMAND_WRITE    (uint8_t)1

/** Device Page Size
*/
#define M24512_EEPROM_PAGE_SIZE (uint16_t)128

/** Device Page Count
*/
#define M24512_EEPROM_PAGES  	(uint16_t)512



M24512::M24512(PinName sda, PinName scl, uint8_t address) : _i2c(sda,scl), _addr(address)
{
	frequency(M24512_DEFAULT_FREQUENCY);
}


M24512::~M24512()
{

}


void M24512::frequency(uint32_t hz)
{
	_i2c.frequency(hz);
}


uint32_t M24512::get_total_memory() const
{
	return (get_page_size() * get_page_count()) / 1024 ;
}


uint16_t M24512::get_page_size() const
{
	return M24512_EEPROM_PAGE_SIZE;
}


uint16_t M24512::get_page_count() const
{
	return M24512_EEPROM_PAGES;
}


M24512::status_t M24512::ready()
{
	int8_t ack;
	char cmd[2] = {0,0};
	int timeout = 20000;

	// Wait for end of write
	do{
		// read from addr 0 with a length of 0 just to check the i2c state
		ack = _i2c.write( _addr | M24512_COMMAND_READ, cmd, 0 );
		if (timeout-- == 0)
		{
			return (ack == 0) ? M24512::M24512_SUCCESS : M24512::M24512_RDY_TIMEOUT;
		}
	}while(ack != 0);

	return (ack == 0) ? M24512::M24512_SUCCESS : M24512::M24512_I2C_ERROR;
}


M24512::status_t M24512::read(uint16_t addr, char* data, uint16_t size)
{
	int ret = 0;
	char cmd[2];

	// check for overflow
	if ( ( addr + size) > (get_page_size() * get_page_count()) )
	{
		return M24512::M24512_MEM_OVERFLOW;
	}

	cmd[0] = addr >> 8;
	cmd[1] = addr;

	// set address to read from
	ret = _i2c.write(_addr | M24512_COMMAND_READ, (const char*)&cmd, 2, true );
	if (ret != 0)
	{
		return M24512::M24512_I2C_ERROR;
	}

	// read data into buffer
	ret = _i2c.read(_addr | M24512_COMMAND_READ, (char*)data, size );
	if (ret != 0)
	{
		return M24512::M24512_I2C_ERROR;
	}

	return ready();
}


M24512::status_t M24512::write_page(uint16_t addr, const char* data, uint16_t size)
{
    /** TODO - Change this to dynamic incase page size increase! */
	char cmd[M24512_EEPROM_PAGE_SIZE];
	int ret = 0;

	// check for overflow
	if ( ( addr + size) > (get_page_size() * get_page_count()) )
	{
		return M24512::M24512_MEM_OVERFLOW;
	}

	// check for page boundary
    /** TODO - Change this to get_page_size incase change in size */
	if (size > M24512_EEPROM_PAGE_SIZE)
	{
		return M24512::M24512_MEM_OVERFLOW;
	}

	cmd[0] = addr >> 8;
	cmd[1] = addr;

	for (uint8_t i = 0;  i < size ; i++)
	{
		cmd[2+i] = data[i];
	}

	ret = _i2c.write(_addr | M24512_COMMAND_WRITE, (const char*)&cmd, size + 2 );
	if (ret != 0)
	{
		return M24512::M24512_I2C_ERROR;
	}

	return ready();

}


M24512::status_t M24512::write(uint16_t addr, const char* data, uint16_t size)
{
	M24512::status_t ret = M24512_SUCCESS;

	int16_t wlen = 0; // write length
	int16_t dlen = size; // data length remaining
	int16_t addr_ofst = 0; // address to write

	while (dlen > 0)
	{
		wlen = ((dlen > get_page_size()) ? get_page_size() : dlen);

		// if addr is not at the start of a page then write bytes until we hit the boundary
		if ( addr_ofst == 0 && (addr % get_page_size()) != 0 )
		{
			wlen = get_page_size() - (addr % get_page_size());
			// check we have enough data to hit end of page if not just write the entire length
			if (size < wlen)
			{
				wlen = size;
			}
		}

		//printf("Write: Addr:%d Write: %d Remain: %d next: %d\n", addr + addr_ofst,  wlen, dlen - wlen , addr_ofst + wlen);

		// write in blocks of %page_size%
		ret = write_page( addr + addr_ofst, data + addr_ofst, wlen );
		if (  ret != M24512::M24512_SUCCESS )
		{
			return ret;
		}

		dlen -= wlen;
		addr_ofst += wlen;
	}

	return ret;
}