123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- inline void _waitForIdleBus() { while (I2C1CON & 0x1f) {} }
- void DS3231::begin()
- {
- if ((_sda_pin == SDA) and (_scl_pin == SCL))
- {
- uint32_t tpgd;
- _use_hw = true;
- pinMode(SDA, OUTPUT);
- digitalWrite(SDA, HIGH);
- IFS0CLR = 0xE0000000; // Clear Interrupt Flag
- IEC0CLR = 0xE0000000; // Disable Interrupt
- I2C1CONCLR = (1 << _I2CCON_ON); // Disable I2C interface
- tpgd = ((F_CPU / 8) * 104) / 125000000;
- I2C1BRG = (F_CPU / (2 * TWI_FREQ) - tpgd) - 2; // Set I2C Speed
- I2C1ADD = DS3231_ADDR; // Set I2C device address
- I2C1CONSET = (1 << _I2CCON_ON) | (1 << _I2CCON_STREN); // Enable I2C Interface
- }
- else
- {
- _use_hw = false;
- pinMode(_scl_pin, OUTPUT);
- }
- }
- void DS3231::_burstRead()
- {
- if (_use_hw)
- {
- _waitForIdleBus(); // Wait for I2C bus to be Idle before starting
- I2C1CONSET = (1 << _I2CCON_SEN); // Send start condition
- if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return; } // Check if there is a bus collision
- while (I2C1CON & (1 << _I2CCON_SEN)) {} // Wait for start condition to finish
- I2C1TRN = (DS3231_ADDR<<1); // Send device Write address
- while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
- {
- I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
- I2C1TRN = (DS3231_ADDR<<1); // Retry send device Write address
- }
- while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
- while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
- I2C1TRN = 0; // Send the register address
- while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
- while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
- _waitForIdleBus(); // Wait for I2C bus to be Idle before starting
- I2C1CONSET = (1 << _I2CCON_RSEN); // Send start condition
- if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return; } // Check if there is a bus collision
- while (I2C1CON & (1 << _I2CCON_RSEN)) {} // Wait for start condition to finish
- I2C1TRN = (DS3231_ADDR<<1) | 1; // Send device Read address
- while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
- {
- I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
- I2C1TRN = (DS3231_ADDR<<1) | 1; // Retry send device Read address
- }
- while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
- while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
- byte dummy = I2C1RCV; // Clear _I2CSTAT_RBF (Receive Buffer Full)
- for (int i=0; i<7; i++)
- {
- _waitForIdleBus(); // Wait for I2C bus to be Idle before continuing
- I2C1CONSET = (1 << _I2CCON_RCEN); // Set RCEN to start receive
- while (I2C1CON & (1 << _I2CCON_RCEN)) {} // Wait for Receive operation to finish
- while (!(I2C1STAT & (1 << _I2CSTAT_RBF))) {} // Wait for Receive Buffer Full
- _burstArray[i] = I2C1RCV; // Read data
- if (i == 6)
- I2C1CONSET = (1 << _I2CCON_ACKDT); // Prepare to send NACK
- else
- I2C1CONCLR = (1 << _I2CCON_ACKDT); // Prepare to send ACK
- I2C1CONSET = (1 << _I2CCON_ACKEN); // Send ACK/NACK
- while (I2C1CON & (1 << _I2CCON_ACKEN)) {} // Wait for ACK/NACK send to finish
- }
- I2C1CONSET = (1 << _I2CCON_PEN); // Send stop condition
- while (I2C1CON & (1 << _I2CCON_PEN)) {} // Wait for stop condition to finish
- }
- else
- {
- _sendStart(DS3231_ADDR_W);
- _waitForAck();
- _writeByte(0);
- _waitForAck();
- _sendStart(DS3231_ADDR_R);
- _waitForAck();
- for (int i=0; i<7; i++)
- {
- _burstArray[i] = _readByte();
- if (i<6)
- _sendAck();
- else
- _sendNack();
- }
- _sendStop();
- }
- }
- uint8_t DS3231::_readRegister(uint8_t reg)
- {
- uint8_t readValue=0;
- if (_use_hw)
- {
- _waitForIdleBus(); // Wait for I2C bus to be Idle before starting
- I2C1CONSET = (1 << _I2CCON_SEN); // Send start condition
- if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return 0xff; }// Check if there is a bus collision
- while (I2C1CON & (1 << _I2CCON_SEN)) {} // Wait for start condition to finish
- I2C1TRN = (DS3231_ADDR<<1); // Send device Write address
- while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
- {
- I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
- I2C1TRN = (DS3231_ADDR<<1); // Retry send device Write address
- }
- while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
- while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
- I2C1TRN = reg; // Send the register address
- while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
- while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
- _waitForIdleBus(); // Wait for I2C bus to be Idle before starting
- I2C1CONSET = (1 << _I2CCON_RSEN); // Send start condition
- if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return 0xff; }// Check if there is a bus collision
- while (I2C1CON & (1 << _I2CCON_RSEN)) {} // Wait for start condition to finish
- I2C1TRN = (DS3231_ADDR<<1) | 1; // Send device Read address
- while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
- {
- I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
- I2C1TRN = (DS3231_ADDR<<1) | 1; // Retry send device Read address
- }
- while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
- while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
- byte dummy = I2C1RCV; // Clear _I2CSTAT_RBF (Receive Buffer Full)
- _waitForIdleBus(); // Wait for I2C bus to be Idle before continuing
- I2C1CONSET = (1 << _I2CCON_RCEN); // Set RCEN to start receive
- while (I2C1CON & (1 << _I2CCON_RCEN)) {} // Wait for Receive operation to finish
- while (!(I2C1STAT & (1 << _I2CSTAT_RBF))) {} // Wait for Receive Buffer Full
- readValue = I2C1RCV; // Read data
- I2C1CONSET = (1 << _I2CCON_ACKDT); // Prepare to send NACK
- I2C1CONSET = (1 << _I2CCON_ACKEN); // Send NACK
- while (I2C1CON & (1 << _I2CCON_ACKEN)) {} // Wait for NACK send to finish
- I2C1CONSET = (1 << _I2CCON_PEN); // Send stop condition
- while (I2C1CON & (1 << _I2CCON_PEN)) {} // Wait for stop condition to finish
- }
- else
- {
- _sendStart(DS3231_ADDR_W);
- _waitForAck();
- _writeByte(reg);
- _waitForAck();
- _sendStart(DS3231_ADDR_R);
- _waitForAck();
- readValue = _readByte();
- _sendNack();
- _sendStop();
- }
- return readValue;
- }
- void DS3231::_writeRegister(uint8_t reg, uint8_t value)
- {
- if (_use_hw)
- {
- _waitForIdleBus(); // Wait for I2C bus to be Idle before starting
- I2C1CONSET = (1 << _I2CCON_SEN); // Send start condition
- if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return; } // Check if there is a bus collision
- while (I2C1CON & (1 << _I2CCON_SEN)) {} // Wait for start condition to finish
- I2C1TRN = (DS3231_ADDR<<1); // Send device Write address
- while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
- {
- I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
- I2C1TRN = (DS3231_ADDR<<1); // Retry send device Write address
- }
- while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
- while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
- I2C1TRN = reg; // Send the 1st data byte
- while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
- while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
- I2C1TRN = value; // Send the 2nd data byte
- while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
- while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
- I2C1CONSET = (1 << _I2CCON_PEN); // Send stop condition
- while (I2C1CON & (1 << _I2CCON_PEN)) {} // Wait for stop condition to finish
- }
- else
- {
- _sendStart(DS3231_ADDR_W);
- _waitForAck();
- _writeByte(reg);
- _waitForAck();
- _writeByte(value);
- _waitForAck();
- _sendStop();
- }
- }
|