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:
parent
0138119bff
commit
7e07da6e60
3 changed files with 153 additions and 17 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue