15#include "i2c_rp2040.h"
16#include "system_rp2040.h"
19using namespace _IO_BANK0_;
20using namespace _RESETS_;
22i2c_rp2040:: i2c_rp2040(uint8_t index,
26 : _initialized(false), _index(index), _sda(sda_pin), _scl(scl_pin), _mode(mode),
27 _restart_on_next(false) {
30 assert((sda_pin <= 28) && (scl_pin <= 29));
32 assert( (((sda_pin-0) % 4) == 0) &&
33 (((scl_pin-1) % 4) == 0) );
35 assert( (((sda_pin-2) % 4) == 0) &&
36 (((scl_pin-3) % 4) == 0) );
38 _i2c = (index==0) ? &I2C0 : &I2C1;
39 _i2c_set = (index==0) ? &I2C0_SET : &I2C1_SET;
40 _i2c_clr = (index==0) ? &I2C0_CLR : &I2C1_CLR;
43i2c_rp2040::~i2c_rp2040() {
52void i2c_rp2040::initialize() {
54 if (_index) RESETS_CLR.RESET.i2c1 = 1;
55 else RESETS_CLR.RESET.i2c0 = 1;
57 _sda.setSEL(GPIO_CTRL_FUNCSEL__i2c);
58 _scl.setSEL(GPIO_CTRL_FUNCSEL__i2c);
61 _i2c->IC_ENABLE.ENABLE = 0;
64 _i2c->IC_CON.MASTER_MODE = 1;
65 _i2c->IC_CON.SPEED = IC_CON_SPEED__FAST;
66 _i2c->IC_CON.IC_10BITADDR_MASTER = 0;
67 _i2c->IC_CON.IC_RESTART_EN = 1;
68 _i2c->IC_CON.IC_SLAVE_DISABLE = 1;
69 _i2c->IC_CON.TX_EMPTY_CTRL = 1;
81int16_t i2c_rp2040::i2cRead (uint16_t addr, uint8_t *rxbuf,
82 uint16_t len,
bool sendStop) {
83 if (!_initialized) initialize();
85 _i2c->IC_ENABLE.ENABLE = 0;
87 _i2c->IC_ENABLE.ENABLE = 1;
90 for (byte_ctr = 0; byte_ctr < len; ++byte_ctr) {
91 bool first = byte_ctr == 0;
92 bool last = byte_ctr == len - 1;
94 while(_i2c->IC_TXFLR == 16) ;
96 uint32_t cmd = 1 << 8;
97 if (first && _restart_on_next) {
100 if (last && sendStop) {
103 _i2c->IC_DATA_CMD = cmd;
105 while(_i2c->IC_RXFLR == 0) ;
107 *rxbuf++ = _i2c->IC_DATA_CMD.DAT;
109 _restart_on_next = !sendStop;
113int16_t i2c_rp2040::i2cWrite(uint16_t addr, uint8_t *txbuf,
114 uint16_t len,
bool sendStop) {
115 if (!_initialized) initialize();
117 _i2c->IC_ENABLE.ENABLE = 0;
119 _i2c->IC_ENABLE.ENABLE = 1;
122 for (byte_ctr = 0; byte_ctr < len; ++byte_ctr) {
123 bool first = byte_ctr == 0;
124 bool last = byte_ctr == len - 1;
126 uint32_t cmd = *txbuf++;
127 if (first && _restart_on_next) {
130 if (last && sendStop) {
133 _i2c->IC_DATA_CMD = cmd;
139 while(!_i2c->IC_RAW_INTR_STAT.TX_EMPTY) ;
141 _restart_on_next = !sendStop;
145void i2c_rp2040::setSpeed(uint32_t freq) {
146 if (!_initialized) initialize();
149 uint32_t freq_in = CLK_SYS;
152 uint32_t period = (freq_in + freq / 2) / freq;
153 uint32_t lcnt = period * 3 / 5;
154 uint32_t hcnt = period - lcnt;
160 uint32_t sda_tx_hold_count;
161 if (freq < 1000000) {
165 sda_tx_hold_count = ((freq_in * 3) / 10000000) + 1;
170 sda_tx_hold_count = ((freq_in * 3) / 25000000) + 1;
172 assert(sda_tx_hold_count <= lcnt - 2);
174 _i2c->IC_ENABLE.ENABLE = 0;
176 _i2c->IC_CON.SPEED = IC_CON_SPEED__FAST;
177 _i2c->IC_FS_SCL_HCNT = hcnt;
178 _i2c->IC_FS_SCL_LCNT = lcnt;
179 _i2c->IC_FS_SPKLEN = lcnt < 16 ? 1 : lcnt / 16;
180 _i2c->IC_SDA_HOLD.IC_SDA_TX_HOLD = sda_tx_hold_count;
182 _i2c->IC_ENABLE.ENABLE = 1;