add Wire::end()

This commit is contained in:
hathach 2021-11-26 11:27:27 +07:00
parent 726a943393
commit 7157b88f4a
4 changed files with 75 additions and 29 deletions

View file

@ -77,9 +77,14 @@ void TwoWire::begin(int address)
begin((uint8_t)address);
}
void TwoWire::setClock(uint32_t frequency)
void TwoWire::end(void)
{
TWBR = ((F_CPU / frequency) - 16) / 2;
twi_disable();
}
void TwoWire::setClock(uint32_t clock)
{
twi_setFrequency(clock);
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)

View file

@ -33,6 +33,9 @@
#define BUFFER_LENGTH 32
// WIRE_HAS_END means Wire has end()
#define WIRE_HAS_END 1
class TwoWire : public Stream
{
private:
@ -55,6 +58,7 @@ class TwoWire : public Stream
void begin();
void begin(uint8_t);
void begin(int);
void end();
void setClock(uint32_t);
void beginTransmission(uint8_t);
void beginTransmission(int);

View file

@ -92,6 +92,22 @@ void twi_init(void)
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
}
/*
* Function twi_disable
* Desc disables twi pins
* Input none
* Output none
*/
void twi_disable(void)
{
// disable twi module, acks, and twi interrupt
TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA));
// deactivate internal pullups for twi.
digitalWrite(SDA, 0);
digitalWrite(SCL, 0);
}
/*
* Function twi_slaveInit
* Desc sets slave address and enables interrupt
@ -104,6 +120,22 @@ void twi_setAddress(uint8_t address)
TWAR = address << 1;
}
/*
* Function twi_setClock
* Desc sets twi bit rate
* Input Clock Frequency
* Output none
*/
void twi_setFrequency(uint32_t frequency)
{
TWBR = ((F_CPU / frequency) - 16) / 2;
/* twi bit rate formula from atmega128 manual pg 204
SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
note: TWBR should be 10 or higher for master mode
It is 72 for a 16mhz Wiring board with 100kHz TWI */
}
/*
* Function twi_readFrom
* Desc attempts to become twi bus master and read a
@ -155,24 +187,25 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
TWDR = twi_slarw;
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
}
else
} else {
// send start condition
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
}
// wait for read operation to complete
while(TWI_MRX == twi_state){
continue;
}
if (twi_masterBufferIndex < length)
if (twi_masterBufferIndex < length) {
length = twi_masterBufferIndex;
}
// copy twi buffer to data
for(i = 0; i < length; ++i){
data[i] = twi_masterBuffer[i];
}
return length;
}
@ -235,10 +268,10 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
TWDR = twi_slarw;
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
}
else
} else {
// send start condition
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs
}
// wait for write operation to complete
while(wait && (TWI_MTX == twi_state)){
@ -322,7 +355,7 @@ void twi_reply(uint8_t ack)
if(ack){
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
}else{
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
}
}
@ -382,16 +415,16 @@ ISR(TWI_vect)
TWDR = twi_masterBuffer[twi_masterBufferIndex++];
twi_reply(1);
}else{
if (twi_sendStop)
if (twi_sendStop){
twi_stop();
else {
twi_inRepStart = true; // we're gonna send the START
// don't enable the interrupt. We'll generate the start, but we
// avoid handling the interrupt until we're in the next transaction,
// at the point where we would normally issue the start.
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
twi_state = TWI_READY;
}
} else {
twi_inRepStart = true; // we're gonna send the START
// don't enable the interrupt. We'll generate the start, but we
// avoid handling the interrupt until we're in the next transaction,
// at the point where we would normally issue the start.
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
twi_state = TWI_READY;
}
}
break;
case TW_MT_SLA_NACK: // address sent, nack received
@ -411,6 +444,7 @@ ISR(TWI_vect)
case TW_MR_DATA_ACK: // data received, ack sent
// put byte into buffer
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
__attribute__ ((fallthrough));
case TW_MR_SLA_ACK: // address sent, ack received
// ack if more bytes are expected, otherwise nack
if(twi_masterBufferIndex < twi_masterBufferLength){
@ -422,17 +456,17 @@ ISR(TWI_vect)
case TW_MR_DATA_NACK: // data received, nack sent
// put final byte into buffer
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
if (twi_sendStop)
twi_stop();
else {
twi_inRepStart = true; // we're gonna send the START
// don't enable the interrupt. We'll generate the start, but we
// avoid handling the interrupt until we're in the next transaction,
// at the point where we would normally issue the start.
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
twi_state = TWI_READY;
}
break;
if (twi_sendStop){
twi_stop();
} else {
twi_inRepStart = true; // we're gonna send the START
// don't enable the interrupt. We'll generate the start, but we
// avoid handling the interrupt until we're in the next transaction,
// at the point where we would normally issue the start.
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
twi_state = TWI_READY;
}
break;
case TW_MR_SLA_NACK: // address sent, nack received
twi_stop();
break;
@ -498,6 +532,7 @@ ISR(TWI_vect)
twi_txBufferLength = 1;
twi_txBuffer[0] = 0x00;
}
__attribute__ ((fallthrough));
// transmit first byte from buffer, fall
case TW_ST_DATA_ACK: // byte sent, ack returned
// copy data to output register

View file

@ -39,7 +39,9 @@
#define TWI_STX 4
void twi_init(void);
void twi_disable(void);
void twi_setAddress(uint8_t);
void twi_setFrequency(uint32_t);
uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t);
uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t);
uint8_t twi_transmit(const uint8_t*, uint8_t);