6 #include <satcat5/cfgbus_i2c.h>
10 namespace cfg = satcat5::cfg;
11 namespace log = satcat5::log;
12 namespace util = satcat5::util;
15 static const unsigned DEBUG_VERBOSE = 0;
18 static const u32 CMD_DELAY = 0x0000u;
19 static const u32 CMD_START = 0x0100u;
20 static const u32 CMD_RESTART = 0x0200u;
21 static const u32 CMD_STOP = 0x0300u;
22 static const u32 CMD_TXBYTE = 0x0400u;
23 static const u32 CMD_RXBYTE = 0x0500u;
24 static const u32 CMD_RXFINAL = 0x0600u;
25 static const u32 CFG_NOSTRETCH = (1u << 31);
28 : cfg::
MultiSerial(cfg, devaddr, SATCAT5_I2C_MAXCMD,
29 m_txbuff, SATCAT5_I2C_TXBUFF,
30 m_rxbuff, SATCAT5_I2C_RXBUFF)
36 unsigned refclk_hz,
unsigned baud_hz,
bool clock_stretch)
38 if (DEBUG_VERBOSE > 0)
39 log::Log(log::DEBUG,
"I2C: Reconfig @ baud").
write((u32)baud_hz);
41 u32 div_qtr = util::div_ceil_u32(refclk_hz, 4*baud_hz) - 1;
43 m_ctrl[REGADDR_CFG] = div_qtr;
45 m_ctrl[REGADDR_CFG] = div_qtr | CFG_NOSTRETCH;
55 u8 regbytes, u32 regaddr, u8 nread,
58 bool ok = enqueue_cmd(devaddr, regbytes, regaddr, 0, 0, nread, callback);
60 if (ok && DEBUG_VERBOSE > 0)
68 u8 regbytes, u32 regaddr, u8 nwrite,
const u8* data,
71 bool ok = enqueue_cmd(devaddr, regbytes, regaddr, nwrite, data, 0, callback);
73 if (ok && DEBUG_VERBOSE > 0)
79 bool cfg::I2c::enqueue_cmd(
81 u8 regbytes, u32 regaddr,
82 u8 nwrite,
const u8* data, u8 nread,
86 if (regbytes > 4)
return false;
90 if (devaddr.
is_10b()) ++ndev;
91 unsigned ncmd = 2 + ndev;
92 ncmd += regbytes + nwrite + nread;
93 if ((regbytes || nwrite) && nread)
97 if (!write_check(ncmd, nread))
return false;
100 u16 dev_msb = (devaddr.
m_addr >> 8) & 0xFF;
101 u16 dev_lsb = (devaddr.
m_addr >> 0) & 0xFF;
104 m_tx.write_u16(CMD_START);
105 if (regbytes || nwrite) {
108 util::write_be_u32(regarray, regaddr);
109 const u8* regptr = regarray + 4 - regbytes;
112 m_tx.write_u16(CMD_TXBYTE | dev_msb);
113 m_tx.write_u16(CMD_TXBYTE | dev_lsb);
115 m_tx.write_u16(CMD_TXBYTE | dev_lsb);
117 for (
unsigned a = 0 ; a < regbytes ; ++a)
118 m_tx.write_u16(CMD_TXBYTE | regptr[a]);
119 for (
unsigned a = 0 ; a < nwrite ; ++a)
120 m_tx.write_u16(CMD_TXBYTE | data[a]);
122 if (nread) m_tx.write_u16(CMD_RESTART);
127 m_tx.write_u16(CMD_TXBYTE | dev_msb | 1);
128 m_tx.write_u16(CMD_TXBYTE | dev_lsb);
130 m_tx.write_u16(CMD_TXBYTE | dev_lsb | 1);
132 for (
unsigned a = 1 ; a < nread ; ++a)
133 m_tx.write_u16(CMD_RXBYTE);
134 m_tx.write_u16(CMD_RXFINAL);
136 m_tx.write_u16(CMD_STOP);
139 unsigned idx = write_finish();
140 m_callback[idx] = callback;
141 m_devaddr[idx] = devaddr.
m_addr;
142 m_regaddr[idx] = regaddr;
148 u8 rxbuff[SATCAT5_I2C_RXBUFF];
149 if (DEBUG_VERBOSE || m_callback[idx]) {
151 unsigned nread = m_rx.get_read_ready();
152 m_rx.read_bytes(nread, rxbuff);
153 u8 noack = rxbuff[nread-1];
156 log::Log msg(log::DEBUG,
"I2C: Done");
157 if (noack) msg.
write(
" (noack)");
158 if (DEBUG_VERBOSE > 1) msg.
write(rxbuff, nread-1);
161 if (m_callback[idx]) {
163 m_callback[idx]->i2c_done(
164 noack, devaddr, m_regaddr[idx], nread-1, rxbuff);
Callback interface for cfg::I2cGeneric events.
bool busy() override
Is the I2C controller currently busy?
void read_done(unsigned idx)
Callback when each transaction is finished.
I2c(satcat5::cfg::ConfigBus *cfg, unsigned devaddr)
Constructor links to specified ConfigBus address.
bool read(const satcat5::util::I2cAddr &devaddr, u8 regbytes, u32 regaddr, u8 nread, satcat5::cfg::I2cEventListener *callback=0) override
Add a read operation to the queue.
bool write(const satcat5::util::I2cAddr &devaddr, u8 regbytes, u32 regaddr, u8 nwrite, const u8 *data, satcat5::cfg::I2cEventListener *callback=0) override
Add a write operation to the queue.
void configure(unsigned refclk_hz, unsigned baud_hz, bool clock_stretch=true)
Configure the I2C controller.
Partial driver for the multipurpose serial peripheral.
The Log class creates and formats one log message.
Log & write(const char *str)
Formatting methods for various data types.
Diagnostic logging to UART and/or Ethernet ports.
Conversion function for I2C device addresses.
const u16 m_addr
Native internal address representation.
bool is_10b() const
Is this a 10-bit address?
static constexpr I2cAddr native(u16 addr)
Create I2C address from its native internal representation.
Miscellaneous mathematical utility functions.