RISC-V/V003/i2c/i2cmaster.cpp
2024-05-07 11:46:49 +02:00

85 lines
2.5 KiB
C++

#include "system.h"
#include "i2cmaster.h"
#include "print.h"
I2CMaster::I2CMaster() noexcept {
RCC.APB1PCENR.B.I2C1EN = SET;
RCC.APB2PCENR.B.IOPCEN = SET;
// GPIO Alternate Config - default SCL/PC2, SDA/PC1
GPIOC.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
r.B.CNF1 = 3u;
r.B.MODE1 = 1u;
r.B.CNF2 = 3u;
r.B.MODE2 = 1u;
return r.R;
});
RCC.APB1PRSTR.B.I2C1RST = SET;
RCC.APB1PRSTR.B.I2C1RST = RESET;
I2C1.CTLR2.B.FREQ = 48u;
I2C1.CKCFGR.B.CCR = 480u;
I2C1.CTLR1.B.PE = SET;
}
bool I2CMaster::Send(const unsigned char addr, const unsigned char * data, const unsigned int len) {
bool result = false;
do {
if (! send_address(addr & ~1u)) break;
if (data == nullptr) { return stop_condition(); }
for (unsigned n=0u; n<len; n++) {
const unsigned char to_send = data [n];
if (! wait_for([]() -> bool { return I2C1.STAR1.B.TxE == RESET; })) break;
I2C1.DATAR.B.DATAR = to_send;
}
if (! wait_for([]() -> bool { return I2C1.STAR1.B.BTF == RESET; })) break;
result = true;
} while (false);
return result and stop_condition();
}
bool I2CMaster::Receive (const unsigned char addr, unsigned char * data, const unsigned int len) {
bool result = false;
do {
if (! send_address(addr | 1u)) break;
I2C1.CTLR1.B.ACK = SET;
for (unsigned n=0u; n<len-1; n++) {
if (! wait_for([]() -> bool { return I2C1.STAR1.B.RxNE == RESET; })) break;
data [n] = I2C1.DATAR.B.DATAR;
}
I2C1.CTLR1.B.ACK = RESET;
if (! wait_for([]() -> bool { return I2C1.STAR1.B.RxNE == RESET; })) break;
data [len-1] = I2C1.DATAR.B.DATAR;
result = true;
} while (false);
return result and stop_condition();
}
bool I2CMaster::send_address(const unsigned char addr) {
I2C1.CTLR1.B.START = SET;
if (! wait_for([]() -> bool { return I2C1.STAR1.B.SB == RESET; })) return false;
I2C1.DATAR.B.DATAR = addr;
if (! wait_for([]() -> bool { return I2C1.STAR1.B.ADDR == RESET; })) return false;
volatile unsigned x = I2C1.STAR2.R; (void) x;
return true;
}
bool I2CMaster::stop_condition() {
I2C1.CTLR1.B.STOP = SET;
return wait_for([]() -> bool { return I2C1.CTLR1.B.STOP == SET; });
}
void I2CMaster::FindActive(Print& print) {
const char * blank = " \r";
for (unsigned addr = 0u; addr < 0xFF; addr += 2u) {
print << "addr = " << (int) addr;
if (send_address(addr & ~1u)) {
print << " ... OK\r\n";
} else {
print << blank;
}
stop_condition();
}
print << blank;
}