diff --git a/src/ArduinoInterface.h b/src/ArduinoInterface.h
new file mode 100644
index 0000000..b13a305
--- /dev/null
+++ b/src/ArduinoInterface.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 Bruce MacKinnon KC1FSZ
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#ifndef _ArduinoInterface_h
+#define _ArduinoInterface_h
+
+#include "Arduino.h"
+#include "Wire.h"
+#include "I2CInterface.h"
+
+/**
+ * The standard Ardiuno way of talking to I2C
+ * via the Wire.h library.
+ */
+class ArduinoInterface : public I2CInterface {
+public:
+
+ ArduinoInterface() {
+ Wire.begin();
+ }
+
+ uint8_t check_address(uint8_t i2c_bus_addr) {
+ Wire.beginTransmission(i2c_bus_addr);
+ return Wire.endTransmission();
+ }
+
+ uint8_t read(uint8_t i2c_bus_addr, uint8_t addr) {
+
+ uint8_t reg_val = 0;
+
+ Wire.beginTransmission(i2c_bus_addr);
+ Wire.write(addr);
+ Wire.endTransmission();
+
+ Wire.requestFrom(i2c_bus_addr, (uint8_t)1, (uint8_t)false);
+
+ while(Wire.available())
+ {
+ reg_val = Wire.read();
+ }
+
+ return reg_val;
+ }
+
+ uint8_t write(uint8_t i2c_bus_addr, uint8_t addr, uint8_t data) {
+ Wire.beginTransmission(i2c_bus_addr);
+ Wire.write(addr);
+ Wire.write(data);
+ return Wire.endTransmission();
+ }
+
+ uint8_t write_bulk(uint8_t i2c_bus_addr, uint8_t addr, uint8_t bytes, uint8_t *data) {
+ Wire.beginTransmission(i2c_bus_addr);
+ Wire.write(addr);
+ for(int i = 0; i < bytes; i++)
+ {
+ Wire.write(data[i]);
+ }
+ return Wire.endTransmission();
+ }
+};
+
+#endif
diff --git a/src/I2CInterface.h b/src/I2CInterface.h
new file mode 100644
index 0000000..65aa2fa
--- /dev/null
+++ b/src/I2CInterface.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 Bruce MacKinnon KC1FSZ
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#ifndef _I2CInterface_h
+#define _I2CInterface_h
+
+#include
+
+/**
+ * A generic interface for interacting with an I2C bus
+ */
+class I2CInterface {
+public:
+
+ /**
+ * Determmines whether a device is connected at the specified address.
+ * @return 0 if things are good, -1 if there is a problem.
+ */
+ virtual uint8_t check_address(uint8_t i2c_bus_addr) = 0;
+
+ /**
+ * Standard read operation.
+ * @return The received byte
+ */
+ virtual uint8_t read(uint8_t i2c_bus_addr, uint8_t addr) = 0;
+
+ /**
+ * Standard write operation.
+ * @return Then number of bytes written
+ */
+ virtual uint8_t write(uint8_t i2c_bus_addr, uint8_t addr, uint8_t data) = 0;
+
+ /**
+ * Multi-byte write operation
+ * @return The number of bytes written
+ */
+ virtual uint8_t write_bulk(uint8_t i2c_bus_addr, uint8_t addr, uint8_t bytes, uint8_t *data) = 0;
+};
+
+#endif
diff --git a/src/STM32_HAL_Interface.h b/src/STM32_HAL_Interface.h
new file mode 100644
index 0000000..f2d5f73
--- /dev/null
+++ b/src/STM32_HAL_Interface.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 Bruce MacKinnon KC1FSZ
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#ifndef _STM32_HAL_Interface_h
+#define _STM32_HAL_Interface_h
+
+#include
+// NOTE: Add the appropriate HAL include here:
+#include "stm32f4xx_hal.h"
+
+#include "I2CInterface.h"
+
+// An STM32/HAL based implementation of the I2CInterface.
+//
+// NOT IMPLEMENTED YET!!
+//
+class STM32_HAL_Interface : public I2CInterface {
+public:
+
+ STM32_HAL_Interface(I2C_HandleTypeDef* hi2c)
+ : _hi2c(hi2c),
+ _errorCount(0),
+ _timeoutMs(10) {
+ }
+
+ uint8_t check_address(uint8_t i2c_bus_addr) {
+ HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(_hi2c, (uint16_t)(i2c_bus_addr << 1), 1, _timeoutMs);
+ if (status == HAL_OK) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
+ uint8_t read(uint8_t i2c_bus_addr, uint8_t addr) {
+ uint8_t reg_val = 0;
+ // NOTE: PER HAL DOCUMENTATION, ADDRESS NEEDS TO BE SHIFTED LEFT
+ HAL_StatusTypeDef status = HAL_I2C_Mem_Read(_hi2c, (uint16_t)(i2c_bus_addr << 1), (uint16_t)(addr), 1,
+ ®_val, 1, _timeoutMs);
+ if (status != HAL_OK) {
+ _errorCount++;
+ }
+ return reg_val;
+ }
+
+ uint8_t write(uint8_t i2c_bus_addr, uint8_t addr, uint8_t data) {
+ // NOTE: PER HAL DOCUMENTATION, ADDRESS NEEDS TO BE SHIFTED LEFT
+ HAL_StatusTypeDef status = HAL_I2C_Mem_Write(_hi2c, (uint16_t)(i2c_bus_addr << 1), addr, 1,
+ &data, 1, _timeoutMs);
+ if (status != HAL_OK) {
+ _errorCount++;
+ }
+ return 1;
+ }
+
+ uint8_t write_bulk(uint8_t i2c_bus_addr, uint8_t addr, uint8_t bytes, uint8_t *data) {
+ // NOTE: PER HAL DOCUMENTATION, ADDRESS NEEDS TO BE SHIFTED LEFT
+ HAL_StatusTypeDef status = HAL_I2C_Mem_Write(_hi2c, (uint16_t)(i2c_bus_addr << 1), addr, 1,
+ data, bytes, _timeoutMs);
+ if (status != HAL_OK) {
+ _errorCount++;
+ }
+ return bytes;
+ }
+
+private:
+
+ I2C_HandleTypeDef* _hi2c;
+ int _errorCount;
+ uint32_t _timeoutMs;
+};
+
+#endif
diff --git a/src/TestInterface.h b/src/TestInterface.h
new file mode 100644
index 0000000..5d05179
--- /dev/null
+++ b/src/TestInterface.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 Bruce MacKinnon KC1FSZ
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#ifndef _Test_Interface_h
+#define _Test_Interface_h
+
+#include
+#include
+#include "I2CInterface.h"
+
+// A dummy interface for testing.
+//
+class TestInterface : public I2CInterface {
+public:
+ TestInterface() {
+ printf("TestInterface initialized\n");
+ }
+ uint8_t check_address(uint8_t i2c_bus_addr) {
+ printf("check_address\n");
+ return 0;
+ }
+ uint8_t read(uint8_t i2c_bus_addr, uint8_t addr) {
+ printf("read(%x,%x)\n", i2c_bus_addr, addr);
+ return 0;
+ }
+ uint8_t write(uint8_t i2c_bus_addr, uint8_t addr, uint8_t data) {
+ printf("write(%x, %x, %x)\n", i2c_bus_addr, addr, data);
+ return 0;
+ }
+ uint8_t write_bulk(uint8_t i2c_bus_addr, uint8_t addr, uint8_t bytes, uint8_t *data) {
+ printf("write_bulk(%x, %x, ", i2c_bus_addr, addr);
+ for (int i = 0; i < bytes; i++) {
+ printf("%x ", data[i]);
+ }
+ printf(")\n");
+ return 0;
+ }
+};
+
+#endif
diff --git a/src/si5351.cpp b/src/si5351.cpp
index e140d65..dd62d17 100644
--- a/src/si5351.cpp
+++ b/src/si5351.cpp
@@ -24,10 +24,21 @@
#include
-#include "Arduino.h"
-#include "Wire.h"
-#include "si5351.h"
+// Remove this to turn off the Arduino hardware environment. Arduino
+// is the default.
+#define SI5351_ARDUINO
+
+#if defined(SI5351_ARDUINO)
+ #include "Arduino.h"
+ #include "Wire.h"
+ #include "ArduinoInterface.h"
+ static ArduinoInterface I2C_Interface_Instance;
+#else
+ #include "TestInterface.h"
+ static TestInterface I2C_Interface_Instance;
+#endif
+#include "si5351.h"
/********************/
/* Public functions */
@@ -36,6 +47,24 @@
Si5351::Si5351(uint8_t i2c_addr):
i2c_bus_addr(i2c_addr)
{
+ // Connect to the default I2C interface
+ i2c_interface = &I2C_Interface_Instance;
+
+ setup();
+}
+
+Si5351::Si5351(uint8_t i2c_addr, I2CInterface* i2c):
+ i2c_bus_addr(i2c_addr),
+ i2c_interface(i2c)
+{
+ setup();
+}
+
+/*
+ * Common setup code
+ */
+void Si5351::setup() {
+
xtal_freq[0] = SI5351_XTAL_FREQ;
// Start by using XO ref osc as default for each PLL
@@ -62,13 +91,8 @@ Si5351::Si5351(uint8_t i2c_addr):
*/
bool Si5351::init(uint8_t xtal_load_c, uint32_t xo_freq, int32_t corr)
{
- // Start I2C comms
- Wire.begin();
-
// Check for a device on the bus, bail out if it is not there
- Wire.beginTransmission(i2c_bus_addr);
- uint8_t reg_val;
- reg_val = Wire.endTransmission();
+ uint8_t reg_val = i2c_interface->check_address(i2c_bus_addr);
if(reg_val == 0)
{
@@ -565,7 +589,7 @@ void Si5351::set_pll(uint64_t pll_freq, enum si5351_pll target_pll)
pllb_freq = pll_freq;
}
- delete params;
+ delete [] params;
}
/*
@@ -672,7 +696,7 @@ void Si5351::set_ms(enum si5351_clock clk, struct Si5351RegSet ms_reg, uint8_t i
break;
}
- delete params;
+ delete [] params;
}
/*
@@ -1240,7 +1264,7 @@ void Si5351::set_vcxo(uint64_t pll_freq, uint8_t ppm)
// Write the parameters
si5351_write_bulk(SI5351_PLLB_PARAMETERS, i, params);
- delete params;
+ delete [] params;
// Write the VCXO parameters
vcxo_param = ((vcxo_param * ppm * SI5351_VCXO_MARGIN) / 100ULL) / 1000000ULL;
@@ -1309,40 +1333,17 @@ void Si5351::set_ref_freq(uint32_t ref_freq, enum si5351_pll_input ref_osc)
uint8_t Si5351::si5351_write_bulk(uint8_t addr, uint8_t bytes, uint8_t *data)
{
- Wire.beginTransmission(i2c_bus_addr);
- Wire.write(addr);
- for(int i = 0; i < bytes; i++)
- {
- Wire.write(data[i]);
- }
- return Wire.endTransmission();
-
+ return i2c_interface->write_bulk(i2c_bus_addr, addr, bytes, data);
}
uint8_t Si5351::si5351_write(uint8_t addr, uint8_t data)
{
- Wire.beginTransmission(i2c_bus_addr);
- Wire.write(addr);
- Wire.write(data);
- return Wire.endTransmission();
+ return i2c_interface->write(i2c_bus_addr, addr, data);
}
uint8_t Si5351::si5351_read(uint8_t addr)
{
- uint8_t reg_val = 0;
-
- Wire.beginTransmission(i2c_bus_addr);
- Wire.write(addr);
- Wire.endTransmission();
-
- Wire.requestFrom(i2c_bus_addr, (uint8_t)1, (uint8_t)false);
-
- while(Wire.available())
- {
- reg_val = Wire.read();
- }
-
- return reg_val;
+ return i2c_interface->read(i2c_bus_addr, addr);
}
/*********************/
diff --git a/src/si5351.h b/src/si5351.h
index 59c16e9..c407f92 100644
--- a/src/si5351.h
+++ b/src/si5351.h
@@ -29,9 +29,8 @@
#ifndef SI5351_H_
#define SI5351_H_
-#include "Arduino.h"
-#include "Wire.h"
#include
+#include "I2CInterface.h"
/* Define definitions */
@@ -279,7 +278,19 @@ struct Si5351IntStatus
class Si5351
{
public:
+
+ /**
+ * Use this constructor when using the (default) Arduino
+ * I2C interface.
+ */
Si5351(uint8_t i2c_addr = SI5351_BUS_BASE_ADDR);
+
+ /**
+ * Use this constructor when explicitly passing the I2CInterface
+ * object.
+ */
+ Si5351(uint8_t i2c_addr, I2CInterface* i2c);
+
bool init(uint8_t, uint32_t, int32_t);
void reset(void);
uint8_t set_freq(uint64_t, enum si5351_clock);
@@ -318,6 +329,7 @@ class Si5351
enum si5351_pll_input pllb_ref_osc;
uint32_t xtal_freq[2];
private:
+ void setup();
uint64_t pll_calc(enum si5351_pll, uint64_t, struct Si5351RegSet *, int32_t, uint8_t);
uint64_t multisynth_calc(uint64_t, uint64_t, struct Si5351RegSet *);
uint64_t multisynth67_calc(uint64_t, uint64_t, struct Si5351RegSet *);
@@ -330,6 +342,8 @@ class Si5351
uint8_t clkin_div;
uint8_t i2c_bus_addr;
bool clk_first_set[8];
+ // This is a connection to the I2C bus
+ I2CInterface* i2c_interface;
};
#endif /* SI5351_H_ */