/******************************************************************************* * @file mcp4725_i2c.c * @author CandyPops Co. * @version V1.0.0 * @date 2022-09-05 * @brief ******************************************************************************/ /* board driver */ #include #include #include #include #include #include "nrf.h" #include "app_error.h" #include "boards.h" #include "nrfx_gpiote.h" #include "mcp4725_i2c.h" #include "nrf_delay.h" #include "debug_print.h" /* I2C number and slave address for MCP4725 */ #define MCP4725_I2C_ADDR_7bit 0x66 uint8_t MCP4725_I2C_ADDR = MCP4725_I2C_ADDR_7bit << 1; uint16_t _lastValue; uint8_t _powerDownMode; uint32_t _lastWriteEEPROM; void mcp4725_i2c_initialize(void) { SCL_OUT(); SDA_OUT(); SCL_H(); SDA_H(); } static uint8_t mcp4725_i2c_write(uint8_t data) { for(uint8_t i = 0; i < 8; i++) { // MSB first if(data & 0x80) SDA_H(); else SDA_L(); i2c_clock(); data = data << 1; } // read ACK SDA_H(); // leave SDA HI SDA_IN(); // change direction to input on SDA line i2c_delay(); SCL_H(); // clock back up i2c_delay(); uint8_t ack = SDA_READ(); // get the ACK bit SCL_L(); SDA_OUT(); // change direction back to output if(ack) { DBG_PRINTF("ACK Extra=%d,Data=%d\r\n", ack,data); } return ack; } static uint8_t mcp4725_i2c_read(bool ack) { uint8_t data; SDA_H(); // leave SDA HI SDA_IN(); // change direction to input on SDA line data = 0; for(uint8_t i = 0; i < 8; i++) { // MSB first data = data << 1; SCL_H(); do{ }while(SCL_READ() != 0); // Wait for any SCL clock stratching i2c_delay(); if(SDA_READ()) // get the Data bit data |= 1; else data |= 0; SCL_L(); // clock LO i2c_delay(); } SDA_OUT(); // change direction back to output // send ACK if(ack == ACK) SDA_L(); else if(ack == NACK) SDA_H(); i2c_clock(); SDA_H(); // leave with SDA HI return data; } void mcp4725_writeFastMode(const uint16_t value) { uint8_t low = value & 0xFF; uint8_t high = ((value >> 8) & 0x0F); // set C2,c1 == 0,0(FastMode Write) pd1,pd0 == 0,0 (Normal Mode) i2c_start(); mcp4725_i2c_write(MCP4725_I2C_ADDR|TWI_WRITE); // slave address //uint8_t address = MCP4725_I2C_ADDR | TWI_WRITE; //DBG_PRINTF("[I2C] Write to 0x%02X\r\n", address); //oxCC mcp4725_i2c_write(high); // value1 ~ 3 mcp4725_i2c_write(low); i2c_stop(); } void mcp4725_generalCall(const uint8_t gc) { i2c_start(); mcp4725_i2c_write(0x00); // First Byte 0x00 mcp4725_i2c_write(gc); // Second Byte, General Call Reset = 0x06, General Call Wake-Up = 0x09 i2c_stop(); } void mcp4725_init(void) { mcp4725_i2c_initialize(); } // DAC value is reset to EEPROM value // need to reflect this in cached value void mcp4725_powerOnReset(void) { mcp4725_generalCall(MCP4725_GC_RESET); } // _powerDownMode DAC resets to 0 -- PDM EEPROM stays same !!! // need to reflect this in cached value void mcp4725_powerOnWakeUp(void) { mcp4725_generalCall(MCP4725_GC_WAKEUP); } /* 현재 DAC값 읽어서 그 값에 Power Down 넣고 Write */ void mcp4725_PowerDownMode(void) { uint8_t low = 0x00; //read_value & 0xFF; uint8_t high = 0x00; //((read_value >> 8) & 0x0F); high = high | (MCP4725_PDMODE_1K << 4); // set C2,c1 == 0,0(FastMode Write) pd1,pd0 == 0,1 (Power Down Mode, 1Kohm to GND) i2c_start(); mcp4725_i2c_write(MCP4725_I2C_ADDR|TWI_WRITE); // slave address mcp4725_i2c_write(high); // value mcp4725_i2c_write(low); i2c_stop(); } //////////////////////////////////////////////////////////////////////////////// uint16_t mcp4725_readDAC(void) { while(!mcp4725_ready()); uint8_t buffer[3]; mcp4725_readRegister(buffer, 3); uint16_t value = buffer[1]; value = value << 4; value = value + (buffer[2] >> 4); return value; } // ready checks if the last write to EEPROM has been written. // until ready all writes to the MCP4725 are ignored! bool mcp4725_ready(void) { uint8_t buffer[1]; mcp4725_readRegister(buffer, 1); return ((buffer[0] & 0x80) > 0); } void mcp4725_writeRegisterMode(const uint16_t value, uint8_t reg) { uint8_t high = (value / 16); uint8_t low = (value & 0x0F) << 4; reg = reg | (_powerDownMode << 1); i2c_start(); mcp4725_i2c_write(MCP4725_I2C_ADDR|TWI_WRITE); // slave address mcp4725_i2c_write(reg); // configuration mcp4725_i2c_write(high); // value1 ~ 3 mcp4725_i2c_write(low); i2c_stop(); } void mcp4725_readRegister(uint8_t* buffer, const uint8_t length) { i2c_start(); mcp4725_i2c_write(MCP4725_I2C_ADDR|TWI_READ); // slave address with READ switch(length) { case 1: buffer[0] = mcp4725_i2c_read(NACK); // NACK, SDA = 1; break; case 2: buffer[0] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[1] = mcp4725_i2c_read(NACK); // NACK, SDA = 1; break; case 3: buffer[0] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[1] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[2] = mcp4725_i2c_read(NACK); // NACK, SDA = 1; break; case 4: buffer[0] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[1] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[2] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[3] = mcp4725_i2c_read(NACK); // NACK, SDA = 1; break; case 5: buffer[0] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[1] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[2] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[3] = mcp4725_i2c_read(ACK); // ACK, SDA = 0; buffer[4] = mcp4725_i2c_read(NACK); // NACK, SDA = 1; break; default: #if FEATURE_PRINTF DBG_PRINTF("ERR!! mcp4725_i2c_readregister\r\n"); #endif break; } i2c_stop(); } void mcp4725_setValue(const uint16_t value) { if (value == _lastValue) return; if (value > MCP4725_MAXVALUE) return; mcp4725_writeFastMode(value); _lastValue = value; } uint16_t mcp4725_getValue(void) { return _lastValue; } void mcp4725_setPercentage(float percentage) { if ((percentage > 100) || (percentage < 0)) DBG_PRINTF("ERR!!! mcp4725 percentage error\r\n"); mcp4725_setValue(round(percentage * (0.01 * MCP4725_MAXVALUE))); } // unfortunately it is not possible to write a different value // to the DAC and EEPROM simultaneously or write EEPROM only. void mcp4725_writeDAC(const uint16_t value, const bool EEPROM) { if (value > MCP4725_MAXVALUE) #if FEATURE_PRINTF DBG_PRINTF("ERR!!! mcp4725 writeDAC error\r\n"); #endif while(!mcp4725_ready()); mcp4725_writeRegisterMode(value, EEPROM ? MCP4725_DACEEPROM : MCP4725_DAC); _lastValue = value; } uint16_t mcp4725_readEEPROM(void) { while(!mcp4725_ready()); uint8_t buffer[5]; mcp4725_readRegister(buffer, 5); uint16_t value = buffer[3] & 0x0F; value = value << 8; value = value + buffer[4]; return value; } // depending on bool EEPROM the value of PDM is written to // (false) DAC or // (true) DAC & EEPROM, void mcp4725_writePowerDownMode(const uint8_t PDM, const bool EEPROM) { _powerDownMode = (PDM & 0x03); // mask PDM bits only (written later low level) _lastValue = mcp4725_readDAC(); _powerDownMode = mcp4725_readPowerDownModeDAC(); mcp4725_writeDAC(_lastValue, EEPROM); } uint8_t mcp4725_readPowerDownModeEEPROM(void) { while(!mcp4725_ready()); uint8_t buffer[4]; mcp4725_readRegister(buffer, 4); uint8_t value = (buffer[3] >> 5) & 0x03; return value; } uint8_t mcp4725_readPowerDownModeDAC(void) { while(!mcp4725_ready()); // TODO needed? uint8_t buffer[1]; mcp4725_readRegister(buffer, 1); uint8_t value = (buffer[0] >> 1) & 0x03; return value; } void ds_i2c_start(void) { SDA_H();//nrf_gpio_pin_set(I2C_SDA_PIN); SCL_H();//nrf_gpio_pin_set(I2C_SCL_PIN); i2c_delay();//nrf_delay_us(I2C_DELAY_US); SDA_L();//nrf_gpio_pin_clear(I2C_SDA_PIN); i2c_delay();//nrf_delay_us(I2C_DELAY_US); SCL_L();//nrf_gpio_pin_clear(I2C_SCL_PIN); i2c_delay();//nrf_delay_us(I2C_DELAY_US); } void ds_i2c_stop(void) { i2c_delay();//nrf_delay_us(I2C_DELAY_US); SDA_L();//nrf_gpio_pin_clear(I2C_SDA_PIN); SCL_H();// nrf_gpio_pin_set(I2C_SCL_PIN); i2c_delay();//nrf_delay_us(I2C_DELAY_US); SDA_H();//nrf_gpio_pin_set(I2C_SDA_PIN); i2c_delay();//nrf_delay_us(I2C_DELAY_US); } void i2c_write_bit(uint8_t bit) { if (bit) { SDA_H(); } else { SDA_L(); } i2c_delay();//nrf_delay_us(I2C_DELAY_US); SCL_H(); //nrf_gpio_pin_set(SCL_PIN); i2c_delay();//nrf_delay_us(I2C_DELAY_US); SCL_L();//nrf_gpio_pin_clear(SCL_PIN); } uint8_t i2c_read_bit(void) { uint8_t bit; SDA_IN();//nrf_gpio_cfg_input(SDA_PIN, NRF_GPIO_PIN_NOPULL); i2c_delay();//nrf_delay_us(I2C_DELAY_US); SCL_H(); ////nrf_gpio_pin_set(SCL_PIN); i2c_delay();//nrf_delay_us(I2C_DELAY_US); bit = SDA_READ();//nrf_gpio_pin_read(SDA_PIN); SCL_L(); //nrf_gpio_pin_clear(SCL_PIN); SDA_OUT();//nrf_gpio_cfg_output(SDA_PIN); return bit; } uint8_t i2c_write_byte(uint8_t byte) { for (uint8_t i = 0; i < 8; i++) { i2c_write_bit(byte & 0x80); byte <<= 1; } return i2c_read_bit(); // Read ACK/NACK } uint8_t i2c_read_byte(uint8_t ack) { uint8_t byte = 0; SDA_IN();//nrf_gpio_cfg_input(SDA_PIN, NRF_GPIO_PIN_NOPULL); for (uint8_t i = 0; i < 8; i++) { byte <<= 1; byte |= i2c_read_bit(); } SDA_OUT();//nrf_gpio_cfg_output(SDA_PIN); i2c_write_bit(!ack); // Send ACK/NACK return byte; } void i2c_repeated_start(void) { SDA_H();//nrf_gpio_pin_set(SDA_PIN); SCL_H();//nrf_gpio_pin_set(SCL_PIN); i2c_delay();//nrf_delay_us(I2C_DELAY_US); SDA_L();////nrf_gpio_pin_clear(SDA_PIN); i2c_delay();//nrf_delay_us(I2C_DELAY_US); SCL_L();//nrf_gpio_pin_clear(SCL_PIN); } // i2c_start(); // i2c_write_byte(I2C_ADDRESS << 1); // Write address // i2c_write_byte(0x00); // Register address // i2c_write_byte(0xFF); // Data // i2c_stop(); // // Read example // i2c_start(); // i2c_write_byte((I2C_ADDRESS << 1) | 1); // Read address // uint8_t data = i2c_read_byte(0); // Read data with NACK // i2c_stop(); void DS3930_write(uint8_t id, uint8_t addr, uint8_t wdata) { //i2c_start(); // ds_i2c_stop(); ds_i2c_start(); i2c_write_byte(id << 1); // Write address i2c_write_byte(addr); // Register address i2c_write_byte(wdata); // Data // mcp4725_i2c_write(id << 1); // mcp4725_i2c_write(addr); // mcp4725_i2c_write(wdata); // // } //i2c_delay(); //i2c_stop(); ds_i2c_stop(); } uint8_t DS3930_read(uint8_t id, uint8_t addr, uint8_t* rdata) { ds_i2c_start(); i2c_write_byte(id << 1); // Write address i2c_write_byte(addr); // Register address i2c_repeated_start(); i2c_write_byte((id << 1) | 1); // Read address uint8_t data = i2c_read_byte(0); // Read data with NACK ds_i2c_stop(); rdata[0] = data; DBG_PRINTF("Data 0x%x . \r\n", data); //i2c_stop(); return data; } //void CAT24_write(uint8_t id, uint8_t addr, uint8_t* wdata) //{ ////i2c_start(); //// ds_i2c_stop(); // ds_i2c_start(); // i2c_write_byte(id << 1); // Write address // i2c_write_byte(addr); // Register address // i2c_write_byte(wdata); // Data // //// mcp4725_i2c_write(id << 1); //// mcp4725_i2c_write(addr); //// mcp4725_i2c_write(wdata); //// //// } ////i2c_delay(); ////i2c_stop(); // ds_i2c_stop(); //} //uint8_t CAT24_read(uint8_t id, uint8_t addr, uint8_t* rdata,uint8_t length) //{ // ds_i2c_start(); // i2c_write_byte(id << 1); // Write address // i2c_write_byte(addr); // Register address // i2c_repeated_start(); // i2c_write_byte((id << 1) | 1); // Read address // uint8_t data = i2c_read_byte(0); // Read data with NACK // ds_i2c_stop(); // rdata[0] = data; // DBG_PRINTF("Data 0x%x . \r\n", data); // //i2c_stop(); // return data; //}