diff --git a/cores/arduino/HardwareI2C.h b/cores/arduino/HardwareI2C.h new file mode 100644 index 0000000..25bf40e --- /dev/null +++ b/cores/arduino/HardwareI2C.h @@ -0,0 +1,43 @@ +/* + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include +#include "Stream.h" + +class HardwareI2C : public Stream +{ + public: + virtual void begin() = 0; + virtual void begin(uint8_t address) = 0; + virtual void end() = 0; + + virtual void setClock(uint32_t freq) = 0; + + virtual void beginTransmission(uint8_t address) = 0; + virtual uint8_t endTransmission(bool stopBit) = 0; + virtual uint8_t endTransmission(void) = 0; + + virtual uint8_t requestFrom(uint8_t address, size_t len, bool stopBit) = 0; + virtual uint8_t requestFrom(uint8_t address, size_t len) = 0; + + virtual void onReceive(void(*)(int)) = 0; + virtual void onRequest(void(*)(void)) = 0; +}; + diff --git a/cores/arduino/RingBuffer.h b/cores/arduino/RingBuffer.h index 2d58dca..eca8e8b 100644 --- a/cores/arduino/RingBuffer.h +++ b/cores/arduino/RingBuffer.h @@ -27,7 +27,7 @@ // using a ring buffer (I think), in which head is the index of the location // to which to write the next incoming character and tail is the index of the // location from which to read. -#define SERIAL_BUFFER_SIZE 64 +#define RING_BUFFER_SIZE 64 template class RingBufferN @@ -51,7 +51,7 @@ class RingBufferN int nextIndex(int index); }; -typedef RingBufferN RingBuffer; +typedef RingBufferN RingBuffer; template diff --git a/libraries/Wire/keywords.txt b/libraries/Wire/keywords.txt new file mode 100644 index 0000000..74f8557 --- /dev/null +++ b/libraries/Wire/keywords.txt @@ -0,0 +1,35 @@ +####################################### +# Syntax Coloring Map For Wire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +setClock KEYWORD2 +setClockStretchLimit KEYWORD2 +beginTransmission KEYWORD2 +endTransmission KEYWORD2 +requestFrom KEYWORD2 +send KEYWORD2 +receive KEYWORD2 +onReceive KEYWORD2 +onRequest KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +Wire KEYWORD2 +Wire1 KEYWORD2 +Wire2 KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties new file mode 100644 index 0000000..6818aa1 --- /dev/null +++ b/libraries/Wire/library.properties @@ -0,0 +1,9 @@ +name=Wire +version=1.0.0 +author=Bigbits +maintainer= +sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For k210 boards. +paragraph= +category=Signal Input/Output +url=http://arduino.cc/en/Reference/Wire +architectures=riscv diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp new file mode 100644 index 0000000..e51de9d --- /dev/null +++ b/libraries/Wire/src/Wire.cpp @@ -0,0 +1,458 @@ +#include "Arduino.h" +#include "pins_arduino.h" +#include "Wire.h" + +#include "fpioa.h" +#include "i2c.h" + +static int maix_i2c_slave_irq(void *userdata); + +TwoWire::TwoWire(i2c_device_number_t i2c_device) +{ + _i2c_num = i2c_device; + switch(i2c_device) + { + case I2C_DEVICE_0: + sda_func = FUNC_I2C0_SDA; + scl_func = FUNC_I2C0_SCLK; + break; + case I2C_DEVICE_1: + sda_func = FUNC_I2C1_SDA; + scl_func = FUNC_I2C1_SCLK; + break; + case I2C_DEVICE_2: + sda_func = FUNC_I2C2_SDA; + scl_func = FUNC_I2C2_SCLK; + break; + default: + break; + } + +} + +TwoWire::~TwoWire() +{ + //clear +} + +void +TwoWire::begin(uint8_t sda, uint8_t scl, uint32_t frequency) +{ + i2c_clk = frequency; + fpioa_set_function(sda, sda_func); + fpioa_set_function(scl, scl_func); + volatile i2c_t *i2c_adapter = i2c[_i2c_num]; + uint8_t speed_mode = I2C_CON_SPEED_STANDARD; + //i2c_clk_init + sysctl_clock_enable((sysctl_clock_t)(SYSCTL_CLOCK_I2C0 + _i2c_num)); + sysctl_clock_set_threshold((sysctl_threshold_t)(SYSCTL_THRESHOLD_I2C0 + _i2c_num), 3); + + uint32_t v_i2c_freq = sysctl_clock_get_freq((sysctl_clock_t)(SYSCTL_CLOCK_I2C0 + _i2c_num)); + uint16_t v_period_clk_cnt = floor( (v_i2c_freq*1.0 / i2c_clk / 2) + 0.5 ); + + + if(v_period_clk_cnt <= 6) + v_period_clk_cnt = 6; + if(v_period_clk_cnt >= 65525)//65535-10 + v_period_clk_cnt = 65525; + if((i2c_clk>100000) && (i2c_clk<=1000000)) + speed_mode = I2C_CON_SPEED_FAST; + else + speed_mode = I2C_CON_SPEED_HIGH; + i2c_adapter->enable = 0; + i2c_adapter->con = I2C_CON_MASTER_MODE | I2C_CON_SLAVE_DISABLE | I2C_CON_RESTART_EN | + (address_width == 10 ? I2C_CON_10BITADDR_SLAVE : 0) | I2C_CON_SPEED(speed_mode); + i2c_adapter->ss_scl_hcnt = I2C_SS_SCL_HCNT_COUNT(v_period_clk_cnt); + i2c_adapter->ss_scl_lcnt = I2C_SS_SCL_LCNT_COUNT(v_period_clk_cnt); + + i2c_adapter->intr_mask = 0; + i2c_adapter->dma_cr = 0x3; + i2c_adapter->dma_rdlr = 0; + i2c_adapter->dma_tdlr = 4; + i2c_adapter->enable = I2C_ENABLE_ENABLE; + is_master_mode = true; + + i2c_tx_buff = new RingBuffer(); + i2c_rx_buff = new RingBuffer(); + + +} + +void +TwoWire::begin(uint16_t slave_address, uint8_t sda, uint8_t scl) +{ + fpioa_set_function(sda, sda_func); + fpioa_set_function(scl, scl_func); + + volatile i2c_t *i2c_adapter = i2c[_i2c_num]; + + sysctl_clock_enable((sysctl_clock_t)(SYSCTL_CLOCK_I2C0 + _i2c_num)); + sysctl_clock_set_threshold((sysctl_threshold_t)(SYSCTL_THRESHOLD_I2C0 + _i2c_num), 3); + + i2c_adapter->enable = 0; + i2c_adapter->con = I2C_CON_SPEED(1) | I2C_CON_STOP_DET_IFADDRESSED; + i2c_adapter->ss_scl_hcnt = I2C_SS_SCL_HCNT_COUNT(37); + i2c_adapter->ss_scl_lcnt = I2C_SS_SCL_LCNT_COUNT(40); + i2c_adapter->sar = I2C_SAR_ADDRESS(slave_address); + i2c_adapter->rx_tl = I2C_RX_TL_VALUE(0); + i2c_adapter->tx_tl = I2C_TX_TL_VALUE(0); + i2c_adapter->intr_mask = I2C_INTR_MASK_RX_FULL | I2C_INTR_MASK_START_DET | I2C_INTR_MASK_STOP_DET | I2C_INTR_MASK_RD_REQ; + + plic_set_priority((plic_irq_t)(IRQN_I2C0_INTERRUPT + _i2c_num), 1); + plic_irq_register((plic_irq_t)(IRQN_I2C0_INTERRUPT + _i2c_num), maix_i2c_slave_irq, this); + plic_irq_enable((plic_irq_t)(IRQN_I2C0_INTERRUPT + _i2c_num)); + + i2c_adapter->enable = I2C_ENABLE_ENABLE; + is_master_mode = false; + + i2c_tx_buff = new RingBuffer(); + i2c_rx_buff = new RingBuffer(); + +} +void +TwoWire::setTimeOut(uint16_t timeOutMillis) +{ + _timeOutMillis = timeOutMillis; +} + +uint16_t +TwoWire::getTimeOut() +{ + return _timeOutMillis; +} + +void +TwoWire::setClock(uint32_t frequency) +{ + i2c_clk = frequency; + volatile i2c_t *i2c_adapter = i2c[_i2c_num]; + uint8_t speed_mode = I2C_CON_SPEED_STANDARD; + + uint32_t v_i2c_freq = sysctl_clock_get_freq((sysctl_clock_t)(SYSCTL_CLOCK_I2C0 + _i2c_num)); + uint16_t v_period_clk_cnt = floor( (v_i2c_freq*1.0 / i2c_clk / 2) + 0.5 ); + + if(v_period_clk_cnt <= 6) + v_period_clk_cnt = 6; + if(v_period_clk_cnt >= 65525)//65535-10 + v_period_clk_cnt = 65525; + if((i2c_clk>100000) && (i2c_clk<=1000000)) + speed_mode = I2C_CON_SPEED_FAST; + else + speed_mode = I2C_CON_SPEED_HIGH; + i2c_adapter->enable = 0; + i2c_adapter->con = I2C_CON_MASTER_MODE | I2C_CON_SLAVE_DISABLE | I2C_CON_RESTART_EN | + (address_width == 10 ? I2C_CON_10BITADDR_SLAVE : 0) | I2C_CON_SPEED(speed_mode); + i2c_adapter->ss_scl_hcnt = I2C_SS_SCL_HCNT_COUNT(v_period_clk_cnt); + i2c_adapter->ss_scl_lcnt = I2C_SS_SCL_LCNT_COUNT(v_period_clk_cnt); + i2c_adapter->enable = I2C_ENABLE_ENABLE; + +} + +uint32_t +TwoWire::getClock() +{ + return i2c_clk; +} + +int +TwoWire::writeTransmission(uint16_t address, uint8_t* send_buf, size_t send_buf_len, bool sendStop) +{ + volatile i2c_t* i2c_adapter = i2c[_i2c_num]; + size_t fifo_len, index; + //uint32_t abrt_source; + + if(is_master_mode) + i2c_adapter->tar = I2C_TAR_ADDRESS(address); + while (send_buf_len) + { + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = send_buf_len < fifo_len ? send_buf_len : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(*send_buf++); + if (i2c_adapter->tx_abrt_source != 0) + { + i2c_adapter->clr_tx_abrt; + usleep(10); + return 4; + } + send_buf_len -= fifo_len; + } + while ( (i2c_adapter->status & I2C_STATUS_ACTIVITY) || + !(i2c_adapter->status & I2C_STATUS_TFE) ) + { + if (i2c_adapter->tx_abrt_source != 0) + { + i2c_adapter->clr_tx_abrt; + usleep(10); + return 4; + } + } + + return 0; +} + +int +TwoWire::readTransmission(uint16_t address, uint8_t* receive_buf, size_t receive_buf_len, bool sendStop) +{ + size_t fifo_len, index; + // size_t buf_len; + size_t rx_len; + rx_len = receive_buf_len; + // buf_len = rx_len; + volatile i2c_t* i2c_adapter = i2c[_i2c_num]; + uint32_t abrt_source; + + if(is_master_mode) + i2c_adapter->tar = I2C_TAR_ADDRESS(address); + + while (receive_buf_len || rx_len) + { + fifo_len = i2c_adapter->rxflr; + fifo_len = rx_len < fifo_len ? rx_len : fifo_len; + for (index = 0; index < fifo_len; index++) + *receive_buf++ = (uint8_t)i2c_adapter->data_cmd; + rx_len -= fifo_len; + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = receive_buf_len < fifo_len ? receive_buf_len : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_CMD; + abrt_source = i2c_adapter->tx_abrt_source; + if (abrt_source != 0) + { + i2c_adapter->clr_tx_abrt; + usleep(10); + // if(receive_buf_len == buf_len) + + + return 4; + // retur_buf_len -= fifo_len; + } + receive_buf_len -= fifo_len; + } + + return 0; +} + +void +TwoWire::beginTransmission(uint16_t address) +{ + transmitting = 1; + txAddress = address; +} + +uint8_t +TwoWire::endTransmission(bool sendStop) //结束时从rxbuff发送数据? +{ + int state = -1; + int index = 0; + uint8_t temp = 0; + size_t tx_data_length = i2c_tx_buff->available(); + if(tx_data_length == 0){ + state = readTransmission(txAddress, &temp, 1, sendStop); + return state; + } + uint8_t tx_data[RING_BUFFER_SIZE]; + while(i2c_tx_buff->available()) + { + tx_data[index++] = i2c_tx_buff->read_char(); + } + state = writeTransmission(txAddress, tx_data, tx_data_length,sendStop); + return state; +} + +uint8_t +TwoWire::requestFrom(uint16_t address, uint8_t size, bool sendStop) //请求数据,存入rxbuff,供read读 +{ + int state,index = 0; + uint8_t rx_data[RING_BUFFER_SIZE]; + state = readTransmission(address, rx_data, size, sendStop); + if(0 == state){ + while(size) + { + i2c_rx_buff->store_char(rx_data[index++]); + size--; + } + } + return state; +} + +size_t +TwoWire::write(uint8_t data) //写到txbuff +{ + if(transmitting) { + i2c_tx_buff->store_char(data); + } + return 0; +} + +size_t +TwoWire::write(const uint8_t *data, int quantity) +{ + for(size_t i = 0; i < quantity; ++i) { + if(!write(data[i])) { + return i; + } + } + return quantity; +} + +int TwoWire::available(void) //rxbuff.available +{ + return i2c_rx_buff->available(); +} + +int TwoWire::read(void) //rxbuff.read +{ + return i2c_rx_buff->read_char(); +} + +int TwoWire::peek(void) +{ + return i2c_rx_buff->peek(); +} + +int TwoWire::flush(void) +{ + i2c_rx_buff->clear(); + i2c_tx_buff->clear(); + return 0; +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) +{ + return requestFrom(static_cast(address), static_cast(quantity), static_cast(sendStop)); +} + +uint8_t TwoWire::requestFrom(uint16_t address, uint8_t quantity, uint8_t sendStop) +{ + return requestFrom(address, static_cast(quantity), static_cast(sendStop)); +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) +{ + return requestFrom(static_cast(address), static_cast(quantity), true); +} + +uint8_t TwoWire::requestFrom(uint16_t address, uint8_t quantity) +{ + return requestFrom(address, static_cast(quantity), true); +} + +uint8_t TwoWire::requestFrom(int address, int quantity) +{ + return requestFrom(static_cast(address), static_cast(quantity), true); +} + +uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) +{ + return static_cast(requestFrom(static_cast(address), static_cast(quantity), static_cast(sendStop))); +} + +void TwoWire::beginTransmission(int address) +{ + beginTransmission(static_cast(address)); +} + +void TwoWire::beginTransmission(uint8_t address) +{ + beginTransmission(static_cast(address)); +} + +uint8_t TwoWire::endTransmission(void) +{ + return endTransmission(true); +} + +bool +TwoWire::busy(void){ + return false; +} + +void +TwoWire::onReceive( void (*handler)(int) ) +{ + slave_recv_handler = handler; +} +void +TwoWire::onRequest( void (*handler)(void) ) +{ + slave_send_handler = handler; +} + +void +TwoWire::on_receive(uint8_t rec_data) +{ + if(slave_irq_event_start) + { + i2c_rx_buff->store_char(rec_data); + (*slave_recv_handler)((int)1);//此处跳到接收事件函数 + } + return; +} + +uint8_t +TwoWire::on_transmit() +{ + if(slave_irq_event_start){ + (*slave_send_handler)();//跳到发送事件函数 + return i2c_tx_buff->read_char(); + } + return 0; +} + +uint8_t +TwoWire::on_event(i2c_event_t event) +{ + if(event == I2C_EV_START) + slave_irq_event_start = true ; + else + slave_irq_event_start = false; + return 0; +} + +static int maix_i2c_slave_irq(void *userdata) +{ + auto &driver = *reinterpret_cast(userdata); + volatile i2c_t *i2c_adapter = i2c[driver._i2c_num]; + uint32_t status = i2c_adapter->intr_stat; + if (status & I2C_INTR_STAT_START_DET) + { + driver.on_event(I2C_EV_START); + readl(&i2c_adapter->clr_start_det); + } + if (status & I2C_INTR_STAT_RX_FULL) + { + driver.on_receive(i2c_adapter->data_cmd); + } + if (status & I2C_INTR_STAT_RD_REQ) + { + i2c_adapter->data_cmd = driver.on_transmit(); + readl(&i2c_adapter->clr_rd_req); + } + if (status & I2C_INTR_STAT_STOP_DET) + { + driver.on_event(I2C_EV_STOP); + readl(&i2c_adapter->clr_stop_det); + } + return 0; +} + + +void +TwoWire::scan(){ + uint8_t temp; + for (int addr = 0x08; addr < 0x78; ++addr) { + // int ret = i2c_p->writeto(self, addr, NULL, 0, true); + // printf("find %x\n",addr); + int ret = readTransmission(addr,&temp, 1, 1); + // printf("ret:%x\n",ret); + if (ret == 0) { + Serial.print("SCAN Find device:"); + Serial.println(addr,HEX); + } + } +} + +TwoWire Wire = TwoWire(I2C_DEVICE_0); +TwoWire Wire1 = TwoWire(I2C_DEVICE_1); +TwoWire Wire2 = TwoWire(I2C_DEVICE_2); \ No newline at end of file diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h new file mode 100644 index 0000000..fc9fb06 --- /dev/null +++ b/libraries/Wire/src/Wire.h @@ -0,0 +1,126 @@ +#ifndef TwoWire_h +#define TwoWire_h + +#include "Arduino.h" +#include "Stream.h" +#include "RingBuffer.h" + +#include "fpioa.h" +#include "i2c.h" + +#define I2C_BUFFER_LENGTH 128 + +#define I2C_CON_SPEED_STANDARD 1 // <=100Kbit/s +#define I2C_CON_SPEED_FAST 2 // <=400Kbit/s or <=1000Kbit/s +#define I2C_CON_SPEED_HIGH 3 // <=3.4Mbit/s + +typedef void(*user_onRequest)(void); +typedef void(*user_onReceive)(uint8_t*, int); + +class TwoWire : public Stream +{ +public: + i2c_device_number_t _i2c_num; + + TwoWire(i2c_device_number_t i2c_device); + ~TwoWire(); + void begin(uint8_t sda = SDA, uint8_t scl = SCL, uint32_t frequency = 500000); + void begin(uint16_t slave_address, uint8_t sda = SDA, uint8_t scl = SCL); + + void setClock(uint32_t frequency); + uint32_t getClock(); + + void setTimeOut(uint16_t timeOutMillis); + uint16_t getTimeOut(); + + int writeTransmission(uint16_t address, uint8_t* send_buf, size_t send_buf_len, bool sendStop); + int readTransmission(uint16_t address, uint8_t* receive_buf, size_t receive_buf_len, bool sendStop); + + void beginTransmission(uint16_t address); + void beginTransmission(uint8_t address); + void beginTransmission(int address); + + uint8_t endTransmission(bool sendStop); + uint8_t endTransmission(void); + + uint8_t requestFrom(uint16_t address, uint8_t size, bool sendStop); + uint8_t requestFrom(uint16_t address, uint8_t size, uint8_t sendStop); + uint8_t requestFrom(uint16_t address, uint8_t size); + uint8_t requestFrom(uint8_t address, uint8_t size, uint8_t sendStop); + uint8_t requestFrom(uint8_t address, uint8_t size); + uint8_t requestFrom(int address, int size, int sendStop); + uint8_t requestFrom(int address, int size); + + size_t write(uint8_t); + size_t write(const uint8_t *, int); + int available(void); + int read(void); + int peek(void); + int flush(void); + + inline int write(const char * s) + { + return write((uint8_t*) s, strlen(s)); + } + inline int write(unsigned long n) + { + return write((uint8_t)n); + } + inline int write(long n) + { + return write((uint8_t)n); + } + inline int write(unsigned int n) + { + return write((uint8_t)n); + } + inline int write(int n) + { + return write((uint8_t)n); + } + + void onReceive( void (*)(int) ); + void onRequest( void (*)(void) ); + + uint8_t on_event(i2c_event_t event); + uint8_t on_transmit(); + void on_receive(uint8_t rec_data); + + bool busy(); + + void scan(); + +private: + uint16_t i2c_slave_address; + bool is_master_mode = false; + uint32_t address_width = 7; + uint8_t sda = FPIOA_NUM_IO; + uint8_t scl = FPIOA_NUM_IO; + uint32_t i2c_clk; + fpioa_function_t sda_func; + fpioa_function_t scl_func; + + RingBuffer *i2c_tx_buff; + RingBuffer *i2c_rx_buff; + + uint16_t txAddress; + uint8_t transmitting; + + uint16_t _timeOutMillis; + + bool slave_irq_event_start = false; + + void (*slave_recv_handler)(int) ; + void (*slave_send_handler)(void) ; + +}; + + + +extern volatile i2c_t* const i2c[3]; + +extern TwoWire Wire; +extern TwoWire Wire1; +extern TwoWire Wire2; + +#endif //TwoWire_h \ No newline at end of file diff --git a/variants/standard/sipeed_go.h b/variants/standard/sipeed_go.h index 682ec42..23f8775 100644 --- a/variants/standard/sipeed_go.h +++ b/variants/standard/sipeed_go.h @@ -62,8 +62,8 @@ extern class UARTClass Serial3; #define RX1 6 #define TX1 7 -#define SDA 10 -#define SCL 9 +#define SDA 31 +#define SCL 30 static const uint8_t SS = SPI0_CS0 ; static const uint8_t MOSI = SPI0_MOSI; diff --git a/variants/standard/sipeedm1.h b/variants/standard/sipeedm1.h index 9ef0495..867788a 100644 --- a/variants/standard/sipeedm1.h +++ b/variants/standard/sipeedm1.h @@ -62,8 +62,8 @@ extern class UARTClass Serial3; #define RX1 6 #define TX1 7 -#define SDA 10 -#define SCL 9 +#define SDA 31 +#define SCL 30 static const uint8_t SS = SPI0_CS0 ; static const uint8_t MOSI = SPI0_MOSI;