EEPROM-Sim/eeprom.cpp
2024-01-17 12:47:10 +01:00

121 lines
3.4 KiB
C++

#include <ranges>
#include <bcm2835.h>
#include "util.hpp"
/* ADDRESS SETUP TIME
* depends on clock frequency, see datasheet. max 150@2MHz
* address is set after setup time (tADS) and is being hold for address hold time (tAH)
*
*
*/
constexpr uint64_t addressSetupTimeUS = 1; // 300e-9 s
class EEPROM {
EEPROM(const IOPins& ioPins, const AddressPins& addressPins, const Pin& pinCEb, const Pin& pinWEb, const Pin& pinOEb) {
}
}
void initPins() {
// set to input and pullup
auto setPinsInput = []<std::ranges::forward_range T>(const T& t) {
for (auto it = t.begin(); it != t.end(); it++) {
bcm2835_gpio_fsel(*it, BCM2835_GPIO_FSEL_INPT);
/* bcm2835_gpio_set_pud(*it, BCM2835_GPIO_PUD_UP); */
bcm2835_gpio_set_pud(*it, BCM2835_GPIO_PUD_OFF);
}
};
setPinsInput(addressPins);
setPinsInput(dataPins);
setPinsInput(controlPins);
}
void setIODirection(uint8_t direction) {
for (int i = 0; i < dataPins.size(); i++) {
bcm2835_gpio_fsel(dataPins.at(i), direction);
}
}
bool isChipEnabled() {
return !bcm2835_gpio_lev(CEb);
}
inline bool isRead() {
return bcm2835_gpio_lev(RWb);
}
uint16_t readAddress() {
uint16_t address = 0;
for (int i = 0; i < addressPins.size(); i++) {
address |= (bcm2835_gpio_lev(addressPins.at(i)) << i);
}
return address;
}
uint8_t readData() {
uint8_t address = 0;
for (int i = 0; i < dataPins.size(); i++) {
address |= (bcm2835_gpio_lev(dataPins.at(i)) << i);
}
return address;
}
inline void waitForFallingEdge(uint8_t pin) {
while (bcm2835_gpio_lev(pin) == LOW);
while (bcm2835_gpio_lev(pin) == HIGH);
}
inline void waitForRisingEdge(uint8_t pin) {
while (bcm2835_gpio_lev(pin) == HIGH);
while (bcm2835_gpio_lev(pin) == LOW);
}
inline void waitForEdge(uint8_t pin) {
if (bcm2835_gpio_lev(pin) == HIGH) {
while (bcm2835_gpio_lev(pin) == HIGH);
return;
}
else {
while (bcm2835_gpio_lev(pin) == LOW);
return;
}
}
/**
* @brief Simulate an AT28C256 EEPROM
* @details
* While the CEb is low, constantly read the address and put the corresponding data on the bus.
* While CEb is high, set data pins to input.
*/
void simulateEEPROM(std::stop_token token, std::array<char, UINT16_MAX> data) {
initPins();
printf("Begin EEPROM simulation\n");
uint16_t lastAddress = 0;
bool outputActive = false;
while (!token.stop_requested()) {
uint16_t currentAddress = readAddress();
bool chipEnabled = isChipEnabled();
if (chipEnabled && (!outputActive || (currentAddress != lastAddress))) {
setIODirection(BCM2835_GPIO_FSEL_OUTP);
outputActive = true;
uint32_t valueMask = byteToMask(data.at(currentAddress), dataPins);
bcm2835_gpio_write_mask(valueMask, ioMask);
/* std::cout << ">-" << gz::toBinString(currentAddress) << "[" << gz::toHexString(currentAddress) << "]-" << gz::toBinString(data.at(currentAddress)) << "[" << gz::toHexString(static_cast<uint16_t>(data.at(currentAddress)), 2) << "]"; */
/* std::cout << std::endl; */
}
if (!chipEnabled && outputActive) {
setIODirection(BCM2835_GPIO_FSEL_INPT);
outputActive = false;
}
lastAddress = currentAddress;
}
printf("End EEPROM simulation\n");
}