85 lines
2.5 KiB
C++
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;
|
|
}
|
|
|