150 lines
3.7 KiB
C++
150 lines
3.7 KiB
C++
#pragma once
|
|
#include "stdafx.h"
|
|
#include "BaseEeprom24C0X.h"
|
|
#include "BatteryManager.h"
|
|
|
|
class Eeprom24C02 : public BaseEeprom24C0X
|
|
{
|
|
private:
|
|
void WriteBit(uint8_t &dest, uint8_t value)
|
|
{
|
|
if(_counter < 8) {
|
|
uint8_t mask = ~(1 << (7 - _counter));
|
|
dest = (dest & mask) | (value << (7 - _counter));
|
|
_counter++;
|
|
}
|
|
}
|
|
|
|
void ReadBit()
|
|
{
|
|
if(_counter < 8) {
|
|
_output = (_data & (1 << (7 - _counter))) ? 1 : 0;
|
|
_counter++;
|
|
}
|
|
}
|
|
|
|
public:
|
|
Eeprom24C02(shared_ptr<Console> console)
|
|
{
|
|
_console = console;
|
|
_console->InitializeRam(_romData, 256);
|
|
_console->GetBatteryManager()->LoadBattery(".eeprom256", _romData, 256);
|
|
}
|
|
|
|
~Eeprom24C02()
|
|
{
|
|
SaveBattery();
|
|
}
|
|
|
|
void SaveBattery() override
|
|
{
|
|
_console->GetBatteryManager()->SaveBattery(".eeprom256", _romData, 256);
|
|
}
|
|
|
|
void Write(uint8_t scl, uint8_t sda) override
|
|
{
|
|
if(_prevScl && scl && sda < _prevSda) {
|
|
//"START is identified by a high to low transition of the SDA line while the clock SCL is *stable* in the high state"
|
|
_mode = Mode::ChipAddress;
|
|
_counter = 0;
|
|
_output = 1;
|
|
} else if(_prevScl && scl && sda > _prevSda) {
|
|
//"STOP is identified by a low to high transition of the SDA line while the clock SCL is *stable* in the high state"
|
|
_mode = Mode::Idle;
|
|
_output = 1;
|
|
} else if(scl > _prevScl) {
|
|
//Clock rise
|
|
switch(_mode) {
|
|
default: break;
|
|
case Mode::ChipAddress: WriteBit(_chipAddress, sda); break;
|
|
case Mode::Address: WriteBit(_address, sda); break;
|
|
case Mode::Read: ReadBit(); break;
|
|
case Mode::Write: WriteBit(_data, sda); break;
|
|
case Mode::SendAck: _output = 0; break;
|
|
case Mode::WaitAck:
|
|
if(!sda) {
|
|
_nextMode = Mode::Read;
|
|
_data = _romData[_address];
|
|
}
|
|
break;
|
|
}
|
|
} else if(scl < _prevScl) {
|
|
//Clock fall
|
|
switch(_mode) {
|
|
case Mode::ChipAddress:
|
|
//"Upon a correct compare the X24C02 outputs an acknowledge on the SDA line"
|
|
if(_counter == 8) {
|
|
if((_chipAddress & 0xA0) == 0xA0) {
|
|
_mode = Mode::SendAck;
|
|
_counter = 0;
|
|
_output = 1;
|
|
|
|
//"The last bit of the slave address defines the operation to
|
|
//be performed. When set to one a read operation is
|
|
//selected, when set to zero a write operations is selected"
|
|
if(_chipAddress & 0x01) {
|
|
//"Current Address Read"
|
|
//"Upon receipt of the slave address with the R/W
|
|
//bit set to one, the X24C02 issues an acknowledge
|
|
//and transmits the eight bit word during the next eight clock cycles"
|
|
_nextMode = Mode::Read;
|
|
_data = _romData[_address];
|
|
} else {
|
|
_nextMode = Mode::Address;
|
|
}
|
|
} else {
|
|
//This chip wasn't selected, go back to idle mode
|
|
_mode = Mode::Idle;
|
|
_counter = 0;
|
|
_output = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Mode::Address:
|
|
if(_counter == 8) {
|
|
//Finished receiving all 8 bits of the address, send an ack and then starting writing the value
|
|
_counter = 0;
|
|
_mode = Mode::SendAck;
|
|
_nextMode = Mode::Write;
|
|
_output = 1;
|
|
}
|
|
break;
|
|
|
|
case Mode::Read:
|
|
if(_counter == 8) {
|
|
//Finished sending all 8 bits, wait for an ack
|
|
_mode = Mode::WaitAck;
|
|
_address = (_address + 1) & 0xFF;
|
|
}
|
|
break;
|
|
|
|
case Mode::Write:
|
|
if(_counter == 8) {
|
|
//Finished receiving all 8 bits, send an ack
|
|
_counter = 0;
|
|
_mode = Mode::SendAck;
|
|
_nextMode = Mode::Write;
|
|
if(_address == 0) {
|
|
std::cout << "test";
|
|
}
|
|
_romData[_address] = _data;
|
|
_address = (_address + 1) & 0xFF;
|
|
}
|
|
break;
|
|
|
|
case Mode::SendAck:
|
|
case Mode::WaitAck:
|
|
_mode = _nextMode;
|
|
_counter = 0;
|
|
_output = 1;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
_prevScl = scl;
|
|
_prevSda = sda;
|
|
}
|
|
};
|