1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

add i2c ip draft

Signed-off-by: Niklas Eiling <niklas.eiling@eonerc.rwth-aachen.de>
This commit is contained in:
Niklas Eiling 2023-12-15 10:43:12 +01:00 committed by Niklas Eiling
parent 0138119bff
commit 7e07da6e60
3 changed files with 153 additions and 17 deletions

View file

@ -22,22 +22,29 @@ class I2c : public Node {
public:
friend class I2cFactory;
I2c();
virtual ~I2c();
virtual bool init() override;
bool reset() override;
bool write(std::list<u8> &data);
bool read(std::list<u8> &data, size_t max_read);
bool write(u8 address, std::vector<u8> &data);
bool read(u8 address, std::vector<u8> &data, size_t max_read);
int transmitIntrs;
int receiveIntrs;
int statusIntrs;
private:
static constexpr char registerMemory[] = "Reg";
static constexpr char i2cInterrupt[] = "iic2intc_irpt";
XIic xIic;
XIic_Config xConfig;
std::mutex hwLock;
bool configDone = false;
bool configDone;
bool polling;
};
class I2cFactory : NodeFactory {
public:
@ -53,16 +60,14 @@ private:
}
// Create a concrete IP instance
Core *make() const { return new Dma; };
Core *make() const { return new I2c; };
protected:
virtual void parse(Core &ip, json_t *json) override;
virtual void configurePollingMode(Core &ip, PollingMode mode) override {
dynamic_cast<Dma &>(ip).polling = (mode == POLL);
dynamic_cast<I2c &>(ip).polling = (mode == POLL);
}
};
} // namespace ip
} // namespace fpga
} // namespace villas

View file

@ -26,6 +26,7 @@ set(SOURCES
ips/rtds.cpp
ips/switch.cpp
ips/timer.cpp
ips/i2c.cpp
ips/rtds2gpu/rtds2gpu.cpp
ips/rtds2gpu/xrtds2gpu.c

View file

@ -15,17 +15,137 @@
using namespace villas::fpga::ip;
I2c::I2c() : Node("i2c") {}
I2c::I2c()
: Node(), transmitIntrs(0), receiveIntrs(0), statusIntrs(0), xIic(),
xConfig(), hwLock(), configDone(false), polling(false) {}
I2c::~I2c() {}
bool I2c::init() override {}
static void SendHandler(I2c *i2c, __attribute__((unused)) int bytesSend) {
i2c->transmitIntrs++;
}
static void ReceiveHandler(I2c *i2c, __attribute__((unused)) int bytesSend) {
i2c->receiveIntrs++;
}
static void StatusHandler(I2c *i2c, __attribute__((unused)) int event) {
i2c->statusIntrs++;
}
bool I2c::reset() override {}
bool I2c::init() {
int ret;
if (!configDone) {
throw RuntimeError("I2C configuration not done");
}
ret = XIic_CfgInitialize(&xIic, &xConfig, xConfig.BaseAddress);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to initialize I2C");
}
bool I2c::write(std::list<u8> &data) {}
XIic_SetSendHandler(&xIic, this, (XIic_Handler)SendHandler);
XIic_SetRecvHandler(&xIic, this, (XIic_Handler)ReceiveHandler);
XIic_SetStatusHandler(&xIic, this, (XIic_StatusHandler)StatusHandler);
bool I2c::read(std::list<u8> &data, size_t max_read) {}
irqs[i2cInterrupt].irqController->enableInterrupt(irqs[i2cInterrupt],
polling);
return true;
}
bool I2c::reset() { return true; }
bool I2c::write(u8 address, std::vector<u8> &data) {
int ret;
ret =
XIic_SetAddress(&xIic, XII_ADDR_TO_SEND_TYPE, static_cast<int>(address));
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to set I2C address");
}
transmitIntrs = 0;
xIic.Stats.TxErrors = 0;
int retries = 10;
while (xIic.Stats.TxErrors != 0 && retries > 0) {
ret = XIic_Start(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to start I2C");
}
ret = XIic_MasterSend(&xIic, data.data(), data.size());
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to send I2C data");
}
int intrRetries = 10;
while (transmitIntrs == 0 && intrRetries > 0) {
irqs[i2cInterrupt].irqController->waitForInterrupt(
irqs[i2cInterrupt].num);
XIic_InterruptHandler(&xIic);
--intrRetries;
}
--retries;
}
ret = XIic_Stop(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to stop I2C");
}
if (retries == 0) {
throw RuntimeError("Failed to send I2C data");
}
return true;
}
bool I2c::read(u8 address, std::vector<u8> &data, size_t max_read) {
int ret;
data.resize(data.size() + max_read);
u8 *dataPtr = data.data() + data.size() - max_read;
ret =
XIic_SetAddress(&xIic, XII_ADDR_TO_SEND_TYPE, static_cast<int>(address));
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to set I2C address");
}
receiveIntrs = 0;
ret = XIic_Start(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to start I2C");
}
int retries = 10;
while (xIic.Stats.TxErrors != 0 && retries > 0) {
ret = XIic_Start(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to start I2C");
}
ret = XIic_MasterRecv(&xIic, dataPtr, max_read);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to receive I2C data");
}
int intrRetries = 10;
while (receiveIntrs == 0 && intrRetries > 0) {
irqs[i2cInterrupt].irqController->waitForInterrupt(
irqs[i2cInterrupt].num);
XIic_InterruptHandler(&xIic);
--intrRetries;
}
--retries;
}
ret = XIic_Stop(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to stop I2C");
}
if (retries == 0) {
throw RuntimeError("Failed to send I2C data");
}
return XST_SUCCESS;
}
void I2cFactory::parse(Core &ip, json_t *cfg) {
NodeFactory::parse(ip, cfg);
@ -33,17 +153,27 @@ void I2cFactory::parse(Core &ip, json_t *cfg) {
auto &i2c = dynamic_cast<I2c &>(ip);
int i2c_frequency = 0;
char *component_name = nullptr;
json_error_t err;
int ret = json_unpack_ex(
cfg, &err, 0, "{ s: { s?: i, s?: i, s?: i, s?: i, s?: i} }", "parameters",
"c_iic_freq", &i2c_frequency, "c_ten_bit_adr", &i2c.xConfig.Has10BitAddr,
"c_gpo_width", &i2c.xConfig.GpOutWidth, "component_name",
&i2c.xConfig.Name, "c_baseaddr", &i2c.xConfig.BaseAddress);
if (ret != 0)
"c_gpo_width", &i2c.xConfig.GpOutWidth, "component_name", &component_name,
"c_baseaddr", &i2c.xConfig.BaseAddress);
if (ret != 0) {
throw ConfigError(cfg, err, "", "Failed to parse DMA configuration");
}
if (component_name != nullptr) {
char last_letter = component_name[strlen(component_name) - 1];
if (last_letter > '0' && last_letter <= '9') {
i2c.xConfig.DeviceId = atoi(&last_letter);
} else {
throw RuntimeError("Invalid device ID in component name");
}
}
dma.configDone = true;
i2c.configDone = true;
}
static I2cFactory f;