From 035e464f9db8b689e58a4f3fe277bd9eaeedf900 Mon Sep 17 00:00:00 2001 From: lynxeyed-atsu Date: Sat, 12 May 2012 16:36:44 +0900 Subject: added Wire class but master only --- src/core/Wire.cpp | 519 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 519 insertions(+) create mode 100755 src/core/Wire.cpp (limited to 'src/core/Wire.cpp') diff --git a/src/core/Wire.cpp b/src/core/Wire.cpp new file mode 100755 index 0000000..04150cf --- /dev/null +++ b/src/core/Wire.cpp @@ -0,0 +1,519 @@ +#include "Wire.h" +#include +#include +#include + + +void i2c_startbit(int sda, int scl); +void i2c_stopbit(int sda, int scl); +void i2c_begin_transmission(int sda, int scl, unsigned char address); +uint8_t i2c_request_from(int sda, int scl, unsigned char address, unsigned char* data, unsigned char counter); +uint8_t i2c_recv_byte(int sda, int scl, WIRE_ACK_STATE ack); +uint8_t i2c_read(int sda, int scl, uint8_t addr, uint8_t* data, uint8_t nbytes); +WIRE_ACK_STATE i2c_write(int sda, int scl, uint8_t addr, uint8_t* data, uint8_t nbytes); +WIRE_ACK_STATE i2c_send_byte(int sda, int scl, uint8_t data); +WIRE_ACK_STATE i2c_ping(int sda, int scl,uint8_t addr); + +inline void WAIT(void); +inline int SCL_IN(int scl); +inline int SDA_IN(int sda); +inline void SDA_REL(int sda); +inline void SCL_REL(int scl); +inline void SDA_PUL(int sda); +inline void SCL_PUL(int scl); +inline void SCL_SDA_PUL(int scl,int sda); + +// Initialize Class Variables ////////////////////////////////////////////////// +TwoWire::TwoWire() +{ + rxAddress = 0; + rxBuffer[BUFFER_LENGTH]; + rxBufferIndex = 0; + rxBufferLength = 0; + + txAddress = 0; + txBuffer[BUFFER_LENGTH]; + txBufferIndex = 0; + txBufferLength = 0; + + transmitting = 0; + user_onRequest = NULL; + user_onReceive = NULL; +} + + +void TwoWire::begin(void) +{ + rxBufferIndex = 0; + rxBufferLength = 0; + + txBufferIndex = 0; + txBufferLength = 0; + + sda = 18; + scl = 19; //Arduino's default TWI pins(D18,D19) + + begin(sda, scl); +} + +void TwoWire::begin(int sda,int scl) +{ + rxBufferIndex = 0; + rxBufferLength = 0; + + txBufferIndex = 0; + txBufferLength = 0; + + this->sda = sda; + this->scl = scl; + + digitalWrite(sda,LOW); // 出力に設定したらLowが出力されるようにしておく + digitalWrite(scl,LOW); + + pinMode(sda,INPUT); // 入力(Hi-Z)にしておく + pinMode(sda,INPUT); + +} + +// Slave +void TwoWire::begin(uint8_t address) +{ +// twi_setAddress(address); +// twi_attachSlaveTxEvent(onRequestService); +// twi_attachSlaveRxEvent(onReceiveService); + begin(); +} + +// Slave +void TwoWire::begin(int address) +{ + begin((uint8_t)address); +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) +{ + // clamp to buffer length + if(quantity > BUFFER_LENGTH){ + quantity = BUFFER_LENGTH; + } + // perform blocking read into buffer + //uint8_t read = twi_readFrom(address, rxBuffer, quantity); + uint8_t read = i2c_request_from(sda, scl, address, rxBuffer, quantity); + + // set rx buffer iterator vars + rxBufferIndex = 0; + rxBufferLength = read; + + return read; +} + +uint8_t TwoWire::requestFrom(int address, int quantity) +{ + return requestFrom((uint8_t)address, (uint8_t)quantity); +} + +void TwoWire::beginTransmission(uint8_t address) +{ + // indicate that we are transmitting + transmitting = 1; + // set address of targeted slave + txAddress = address; + // reset tx buffer iterator vars + txBufferIndex = 0; + txBufferLength = 0; +} + +void TwoWire::beginTransmission(int address) +{ + beginTransmission((uint8_t)address); +} + +uint8_t TwoWire::endTransmission(void) +{ + // transmit buffer (blocking) + //signed int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1); + i2c_begin_transmission(sda, scl, txAddress); + WIRE_ACK_STATE st = i2c_write(sda, scl, txAddress, txBuffer, txBufferLength); + + unsigned char res = 0; //return value (0:OK, 1:BUFFER OV, 2:ADDRESS NAK, 3:DATA NAK, 4:Another error) + i2c_stopbit(sda, scl); + switch(st) + { + case ACK: res = 0; break; + case BUFF_OV: res = 1; break; + case ADDR_NAK: res = 2; break; + case AND_MORE: res = 4; break; + default: res = 4; + } + // reset tx buffer iterator vars + txBufferIndex = 0; + txBufferLength = 0; + // indicate that we are done transmitting + transmitting = 0; + return res; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +void TwoWire::send(int8_t data) +{ + if(transmitting){ + // in master transmitter mode + // don't bother if buffer is full + if(txBufferLength >= BUFFER_LENGTH){ + return; + } + // put byte in tx buffer + txBuffer[txBufferIndex] = data; + ++txBufferIndex; + // update amount in buffer + txBufferLength = txBufferIndex; + }else{ + // in slave send mode + // reply to master + //twi_transmit(&data, 1); + } +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +void TwoWire::send(uint8_t* data, uint8_t quantity) +{ + if(transmitting){ + // in master transmitter mode + //ここではデータをバッファに蓄積しているだけ + for(uint8_t i = 0; i < quantity; ++i){ + send(data[i]); + } + + + }else{ + // in slave send mode + // reply to master + //twi_transmit(data, quantity); + } +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +void TwoWire::send(int8_t* data) +{ + send((uint8_t *)data, strlen((const char*)data)); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +void TwoWire::send(int data) +{ + send((uint8_t)data); +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +uint8_t TwoWire::available(void) +{ + return rxBufferLength - rxBufferIndex; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +uint8_t TwoWire::receive(void) +{ + // default to returning null int8_t + // for people using with int8_t strings + uint8_t value = '\0'; + + // get each successive byte on each call + if(rxBufferIndex < rxBufferLength){ + value = rxBuffer[rxBufferIndex]; + ++rxBufferIndex; + } + + return value; +} + +// behind the scenes function that is called when data is received +void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) +{ + // don't bother if user hasn't registered a callback + if(!user_onReceive){ + return; + } + // don't bother if rx buffer is in use by a master requestFrom() op + // i know this drops data, but it allows for slight stupidity + // meaning, they may not have read all the master requestFrom() data yet + if(rxBufferIndex < rxBufferLength){ + return; + } + // copy twi rx buffer into local read buffer + // this enables new reads to happen in parallel + for(uint8_t i = 0; i < numBytes; ++i){ + rxBuffer[i] = inBytes[i]; + } + // set rx iterator vars + rxBufferIndex = 0; + rxBufferLength = numBytes; + // alert user program + user_onReceive(numBytes); +} + +// behind the scenes function that is called when data is requested +void TwoWire::onRequestService(void) +{ + // don't bother if user hasn't registered a callback + if(!user_onRequest){ + return; + } + // reset tx buffer iterator vars + // !!! this will kill any pending pre-master sendTo() activity + txBufferIndex = 0; + txBufferLength = 0; + // alert user program + user_onRequest(); +} + +// sets function called on slave write +void TwoWire::onReceive( void (*function)(int) ) +{ + user_onReceive = function; +} + +// sets function called on slave read +void TwoWire::onRequest( void (*function)(void) ) +{ + user_onRequest = function; +} + +// Preinstantiate Objects //////////// + +TwoWire Wire = TwoWire(); + +//------------------------------------------------------------------------------- +// Lowlevel +//------------------------------------------------------------------------------- + +uint8_t i2c_request_from(int sda, int scl, unsigned char address, unsigned char* data, unsigned char counter) +{ + i2c_startbit(sda, scl); + i2c_ping(sda, scl, address); + uint8_t result_bytes = i2c_read(sda, scl, address, data, counter); //counterは受信要求バイト数 + i2c_stopbit(sda, scl); + return result_bytes; //i2c->st_request_countは実際に受信できたバイト数 +} + +void i2c_begin_transmission(int sda, int scl, unsigned char address) +{ + i2c_startbit(sda, scl); + i2c_ping(sda, scl, address); +} + +WIRE_ACK_STATE i2c_write(int sda, int scl, uint8_t addr, uint8_t* data, uint8_t nbytes) +{ + //uint8_t addr; + uint8_t* data_end = data + nbytes; + if(i2c_send_byte(sda, scl, (addr << 1) | 0x00) != 0) + { + //i2c->st_ack = NAK; + //i2c->st_nack = DATA_NAK; + return ADDR_NAK; + } + while(data != data_end){ + if(i2c_send_byte(sda, scl, *data++) != ACK) + { + //i2c->st_ack = ACK; + return DATA_NAK; + } + } + return ACK; +} + +//戻り値は読み込めたバイト数 +uint8_t i2c_read(int sda, int scl, uint8_t addr, uint8_t* data, uint8_t nbytes) +{ + //uint8_t addr = i2c->st_your_sddress; + uint8_t counter = 0;// = i2c->st_request_count; + uint8_t* data_end = data + nbytes; + if(i2c_send_byte(sda, scl, (addr << 1) | 0x01) != 0) + { + //NAK; + //ADDR_NAK + return counter; + } + while(data != data_end){ + *data = i2c_recv_byte(sda, scl, (data != data_end - 1)?ACK:NAK); + data++; + counter++; + } + //i2c->st_ack = ACK; + //i2c->st_request_count = counter; + return counter; +} + +void i2c_startbit(int sda, int scl) +{ + WAIT(); + if(!SCL_IN(scl) || !SDA_IN(sda)) + { + if(SCL_IN(scl)){ + SCL_PUL(scl); + WAIT(); + } + if(!SDA_IN(sda)){ + SDA_REL(sda); + WAIT(); + } + SCL_REL(scl); + WAIT(); + } + SDA_PUL(sda); + WAIT(); + SCL_PUL(scl); + WAIT(); + /* SCL = SDA = L */ +} + +WIRE_ACK_STATE i2c_send_byte(int sda, int scl, uint8_t data) +{ + /* assume SCL = SDA = L */ + WIRE_ACK_STATE ack; + volatile int i; + for(i = 0; i < 8; i++) + { + if(data & 0x80) + SDA_REL(sda); + else SDA_PUL(sda); + WAIT(); + WAIT(); + SCL_REL(scl); + WAIT(); + WAIT(); + if(i != 7) + data <<= 1; + SCL_PUL(scl); + } + WAIT(); + WAIT(); + SDA_REL(sda); + SCL_REL(scl); + WAIT(); + /*while(SCL_IN == 0);*/ /* スレーブによるクロックの引き延ばし */ + ack = (SDA_IN(sda)==0)? ACK:NAK; + WAIT(); + WAIT(); + SCL_SDA_PUL(sda,scl); + /* SCL = SDA = L */ + return ack; +} + +void i2c_stopbit(int sda, int scl) +{ + /* assume SCL = SDA = L */ + WAIT(); + SCL_REL(scl); + WAIT(); + SDA_REL(sda); + WAIT(); + /* SCL = SDA = H */ +} + +uint8_t i2c_recv_byte(int sda, int scl, WIRE_ACK_STATE ack) +{ + + /* SCL = SDA = L */ + volatile uint8_t data; + volatile int i; + SDA_REL(sda); + for(i = 0, data = 0; i < 8; i++){ + WAIT(); + WAIT(); + SCL_REL(scl); + if(SDA_IN(sda)) + data |= 0x01; + else data &= ~0x01; + WAIT(); + WAIT(); + if(i != 7) + data <<= 1; + SCL_PUL(scl); + } + if(ack) /* ack送信 */ + SDA_REL(sda); + else + SDA_PUL(sda); + WAIT(); + WAIT(); + SCL_REL(scl); + WAIT(); + WAIT(); + SCL_PUL(scl); + SDA_PUL(sda); + /* SCL = SDA = L */ + return data; +} + + + +WIRE_ACK_STATE i2c_ping(int sda, int scl,uint8_t addr) +{ + WIRE_ACK_STATE ack; + //uint8_t addr = i2c->st_your_sddress; + i2c_startbit(sda, scl); + ack = i2c_send_byte(sda, scl, (addr << 1) | 0x00); + i2c_stopbit(sda, scl); + return ack; +} + +//ピンの制御 +//Sxx_PUL = Low +//Sxx_REL = Hi-Z +inline void WAIT(void) +{ + delay(1); +} + +inline int SCL_IN(int scl) +{ + return digitalRead(scl); +} + +inline int SDA_IN(int sda) +{ + return digitalRead(sda); +} + +inline void SDA_REL(int sda) +{ + pinMode(sda, INPUT); //入力=Hi-Z +} + +inline void SCL_REL(int scl) +{ + pinMode(scl, INPUT); //入力=Hi-Z +} + +inline void SDA_PUL(int sda) +{ + digitalWrite(sda, LOW); + pinMode(sda, OUTPUT); //出力=Low +} + +inline void SCL_PUL(int scl) +{ + digitalWrite(scl, LOW); + pinMode(scl, OUTPUT); //出力=Low +} + +inline void SCL_SDA_PUL(int scl,int sda) +{ + digitalWrite(sda, LOW); + digitalWrite(scl, LOW); + pinMode(scl, OUTPUT); //出力=Low + pinMode(sda, OUTPUT); //出力=Low +} + -- cgit v1.2.3