Initial commit: MT firmware project
- BLE peripheral applications - dr_piezo and bladder_patch projects Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
513
project/ble_peripheral/ble_app_bladder_patch/mcp4725_i2c.c
Normal file
513
project/ble_peripheral/ble_app_bladder_patch/mcp4725_i2c.c
Normal file
@@ -0,0 +1,513 @@
|
||||
/*******************************************************************************
|
||||
* @file mcp4725_i2c.c
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/* board driver */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#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;
|
||||
//}
|
||||
|
||||
Reference in New Issue
Block a user