diff --git a/meson.build b/meson.build
index 535edbe8..f4946ade 100644
--- a/meson.build
+++ b/meson.build
@@ -422,7 +422,7 @@ mod17_src = ['platform/targets/Module17/platform.c',
'platform/drivers/baseband/radio_Mod17.cpp',
'platform/drivers/audio/audio_Mod17.c',
'platform/drivers/audio/MAX9814_Mod17.cpp',
- 'platform/drivers/baseband/MCP4551_Mod17.cpp']
+ 'platform/drivers/baseband/MCP4551.c']
mod17_inc = ['platform/targets/Module17']
mod17_def = {'PLATFORM_MOD17': ''}
diff --git a/platform/drivers/baseband/MCP4551.c b/platform/drivers/baseband/MCP4551.c
new file mode 100644
index 00000000..ca27c8b8
--- /dev/null
+++ b/platform/drivers/baseband/MCP4551.c
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright (C) 2021 - 2024 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * Mathis Schmieder DB9MAT *
+ * *
+ * 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 *
+ ***************************************************************************/
+
+#include "MCP4551.h"
+
+// Common WIPER values
+#define MCP4551_WIPER_MID 0x080
+#define MCP4551_WIPER_A 0x100
+#define MCP4551_WIPER_B 0x000
+
+// Command definitions (sent to WIPER register)
+#define MCP4551_CMD_WRITE 0x00
+#define MCP4551_CMD_INC 0x04
+#define MCP4551_CMD_DEC 0x08
+#define MCP4551_CMD_READ 0x0C
+
+
+int mcp4551_init(const struct i2cDevice *i2c, const uint8_t devAddr)
+{
+ return mcp4551_setWiper(i2c, devAddr, MCP4551_WIPER_MID);
+}
+
+int mcp4551_setWiper(const struct i2cDevice *i2c, const uint8_t devAddr,
+ const uint16_t value)
+{
+ uint8_t data[2] =
+ {
+ (uint8_t)(value >> 8 & 0x01) | MCP4551_CMD_WRITE,
+ (uint8_t) value
+ };
+
+ i2c_acquire(i2c);
+ int ret = i2c_write(i2c, devAddr, data, 2, true);
+ i2c_release(i2c);
+
+ return ret;
+}
diff --git a/platform/drivers/baseband/MCP4551.h b/platform/drivers/baseband/MCP4551.h
index 48d7d565..a95e5fff 100644
--- a/platform/drivers/baseband/MCP4551.h
+++ b/platform/drivers/baseband/MCP4551.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2021 - 2023 by Federico Amedeo Izzo IU2NUO, *
+ * Copyright (C) 2021 - 2024 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO *
@@ -25,29 +25,31 @@
#include
#include
#include
+#include
#ifdef __cplusplus
extern "C" {
#endif
-// Common WIPER values
-#define MCP4551_WIPER_MID 0x080
-#define MCP4551_WIPER_A 0x100
-#define MCP4551_WIPER_B 0x000
-
-// Command definitions (sent to WIPER register)
-#define MCP4551_CMD_WRITE 0x00
-#define MCP4551_CMD_INC 0x04
-#define MCP4551_CMD_DEC 0x08
-#define MCP4551_CMD_READ 0x0C
+/**
+ * Initialize the MCP4551 device.
+ *
+ * @param i2c: driver managing the I2C bus the chip is connected to.
+ * @param devAddr: I2C device address of the chip.
+ * @return zero on success, a negative error code otherwise.
+ */
+int mcp4551_init(const struct i2cDevice *i2c, const uint8_t devAddr);
/**
- * Initialise I2C.
+ * Set the MCP4551 wiper to a given position.
+ *
+ * @param i2c: driver managing the I2C bus the chip is connected to.
+ * @param devAddr: I2C device address of the chip.
+ * @param value: new wiper position.
+ * @return zero on success, a negative error code otherwise.
*/
-void i2c_init();
-
-void mcp4551_init(uint8_t addr);
-void mcp4551_setWiper(uint8_t devAddr, uint16_t value);
+int mcp4551_setWiper(const struct i2cDevice *i2c, const uint8_t devAddr,
+ const uint16_t value);
#ifdef __cplusplus
}
diff --git a/platform/drivers/baseband/MCP4551_Mod17.cpp b/platform/drivers/baseband/MCP4551_Mod17.cpp
deleted file mode 100644
index f906327f..00000000
--- a/platform/drivers/baseband/MCP4551_Mod17.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2021 - 2023 by Federico Amedeo Izzo IU2NUO, *
- * Niccolò Izzo IU2KIN *
- * Frederik Saraci IU2NRO *
- * Silvano Seva IU2KWO *
- * Mathis Schmieder DB9MAT *
- * *
- * 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 *
- ***************************************************************************/
-
-#include
-#include
-#include
-#include "MCP4551.h"
-
-/*
- * Implementation of MCP4551 I2C interface.
- *
- * Hardware I2C is not yet implemented. Bit-bang, baby!
- */
-
-void _i2c_start();
-void _i2c_stop();
-void _i2c_write(uint8_t val);
-uint8_t _i2c_read(bool ack);
-
-void i2c_init()
-{
- gpio_setMode(I2C_SDA, INPUT);
- gpio_setMode(I2C_SCL, OUTPUT);
- gpio_clearPin(I2C_SCL);
-}
-
-void mcp4551_init(uint8_t addr)
-{
- mcp4551_setWiper(addr, MCP4551_WIPER_MID);
-}
-
-void mcp4551_setWiper(uint8_t devAddr, uint16_t value)
-{
- _i2c_start();
- _i2c_write(devAddr << 1);
- uint8_t temp = ((value >> 8 & 0x01) | MCP4551_CMD_WRITE);
- _i2c_write(temp);
- temp = (value & 0xFF);
- _i2c_write(temp);
- _i2c_stop();
-}
-
-/*uint16_t i2c_readReg16(uint8_t devAddr, uint8_t reg)
-{
- _i2c_start();
- _i2c_write(devAddr << 1);
- _i2c_write(reg);
- _i2c_start();
- _i2c_write(devAddr | 0x01);
- uint8_t valHi = _i2c_read(true);
- uint8_t valLo = _i2c_read(false);
- _i2c_stop();
-
- return (valHi << 8) | valLo;
-} */
-
-/*
- * Software I2C routine
- */
-
-void _i2c_start()
-{
- gpio_setMode(I2C_SDA, OUTPUT);
-
- /*
- * Lines commented to keep SCL high when idle
- *
- gpio_clearPin(I2C_SCL);
- delayUs(2);
- */
-
- gpio_setPin(I2C_SDA);
- delayUs(5);
-
- gpio_setPin(I2C_SCL);
- delayUs(5);
-
- gpio_clearPin(I2C_SDA);
- delayUs(5);
-
- gpio_clearPin(I2C_SCL);
- delayUs(6);
-}
-
-void _i2c_stop()
-{
- gpio_setMode(I2C_SDA, OUTPUT);
-
- gpio_clearPin(I2C_SCL);
- delayUs(5);
-
- gpio_clearPin(I2C_SDA);
- delayUs(5);
-
- gpio_setPin(I2C_SCL);
- delayUs(5);
-
- gpio_setPin(I2C_SDA);
- delayUs(5);
-
- /*
- * Lines commented to keep SCL high when idle
- *
- gpio_clearPin(I2C_SCL);
- delayUs(5);
- */
-}
-
-void _i2c_write(uint8_t val)
-{
- gpio_setMode(I2C_SDA, OUTPUT);
-
- for(uint8_t i = 0; i < 8; i++)
- {
- gpio_clearPin(I2C_SCL);
- delayUs(1);
-
- if(val & 0x80)
- {
- gpio_setPin(I2C_SDA);
- }
- else
- {
- gpio_clearPin(I2C_SDA);
- }
-
- val <<= 1;
- delayUs(1);
- gpio_setPin(I2C_SCL);
- delayUs(5);
- }
-
- /* Ensure SCL is low before releasing SDA */
- gpio_clearPin(I2C_SCL);
-
- /* Clock cycle for slave ACK/NACK */
- gpio_setMode(I2C_SDA, INPUT_PULL_UP);
- delayUs(5);
- gpio_setPin(I2C_SCL);
- delayUs(5);
- gpio_clearPin(I2C_SCL);
- delayUs(1);
-
- /* Asserting SDA pin allows to fastly bring the line to idle state */
- gpio_setPin(I2C_SDA);
- gpio_setMode(I2C_SDA, OUTPUT);
- delayUs(6);
-}
-
-uint8_t _i2c_read(bool ack)
-{
- gpio_setMode(I2C_SDA, INPUT_PULL_UP);
- gpio_clearPin(I2C_SCL);
-
- uint8_t value = 0;
- for(uint8_t i = 0; i < 8; i++)
- {
- delayUs(5);
- gpio_setPin(I2C_SCL);
- delayUs(5);
-
- value <<= 1;
- value |= gpio_readPin(I2C_SDA);
-
- gpio_clearPin(I2C_SCL);
- }
-
- /*
- * Set ACK/NACK state BEFORE putting SDA gpio to output mode.
- * This avoids spurious spikes which can be interpreted as NACKs
- */
- gpio_clearPin(I2C_SDA);
- gpio_setMode(I2C_SDA, OUTPUT);
- delayUs(5);
- if(!ack) gpio_setPin(I2C_SDA);
-
- /* Clock cycle for ACK/NACK */
- delayUs(5);
- gpio_setPin(I2C_SCL);
- delayUs(5);
- gpio_clearPin(I2C_SCL);
- delayUs(5);
-
- return value;
-}
diff --git a/platform/drivers/baseband/radio_Mod17.cpp b/platform/drivers/baseband/radio_Mod17.cpp
index d41c10ce..9455bbce 100644
--- a/platform/drivers/baseband/radio_Mod17.cpp
+++ b/platform/drivers/baseband/radio_Mod17.cpp
@@ -35,8 +35,8 @@ void radio_init(const rtxStatus_t *rtxState)
radioStatus = OFF;
- mcp4551_setWiper(SOFTPOT_TX, mod17CalData.tx_wiper);
- mcp4551_setWiper(SOFTPOT_RX, mod17CalData.rx_wiper);
+ mcp4551_setWiper(&i2c1, SOFTPOT_TX, mod17CalData.tx_wiper);
+ mcp4551_setWiper(&i2c1, SOFTPOT_RX, mod17CalData.rx_wiper);
}
void radio_terminate()
@@ -74,8 +74,8 @@ void radio_enableRx()
{
radioStatus = RX;
- mcp4551_setWiper(SOFTPOT_TX, mod17CalData.tx_wiper);
- mcp4551_setWiper(SOFTPOT_RX, mod17CalData.rx_wiper);
+ mcp4551_setWiper(&i2c1, SOFTPOT_TX, mod17CalData.tx_wiper);
+ mcp4551_setWiper(&i2c1, SOFTPOT_RX, mod17CalData.rx_wiper);
// Module17 PTT output is open drain. This means that, on MCU side, we have
// to assert the gpio to bring it to low state.
@@ -89,8 +89,8 @@ void radio_enableTx()
{
radioStatus = TX;
- mcp4551_setWiper(SOFTPOT_TX, mod17CalData.tx_wiper);
- mcp4551_setWiper(SOFTPOT_RX, mod17CalData.rx_wiper);
+ mcp4551_setWiper(&i2c1, SOFTPOT_TX, mod17CalData.tx_wiper);
+ mcp4551_setWiper(&i2c1, SOFTPOT_RX, mod17CalData.rx_wiper);
max9814_setGain(mod17CalData.mic_gain);
if(mod17CalData.ptt_out_level)
diff --git a/platform/targets/Module17/hwconfig.h b/platform/targets/Module17/hwconfig.h
index 2c8a69a0..5f3c1d50 100644
--- a/platform/targets/Module17/hwconfig.h
+++ b/platform/targets/Module17/hwconfig.h
@@ -22,9 +22,12 @@
#ifndef HWCONFIG_H
#define HWCONFIG_H
+#include
#include
#include "pinmap.h"
+extern const struct i2cDevice i2c1;
+
/* Screen dimensions */
#define CONFIG_SCREEN_WIDTH 128
#define CONFIG_SCREEN_HEIGHT 64
diff --git a/platform/targets/Module17/pinmap.h b/platform/targets/Module17/pinmap.h
index 4d86e190..dbad8e43 100644
--- a/platform/targets/Module17/pinmap.h
+++ b/platform/targets/Module17/pinmap.h
@@ -61,9 +61,9 @@
#define POWER_SW GPIOA,15
/* I2C for MCP4551 */
-#define I2C_SDA GPIOB,7
-#define I2C_SCL GPIOB,6
-#define SOFTPOT_RX 0x2E
-#define SOFTPOT_TX 0x2F
+#define I2C1_SDA GPIOB,7
+#define I2C1_SCL GPIOB,6
+#define SOFTPOT_RX 0x2E
+#define SOFTPOT_TX 0x2F
#endif /* PINMAP_H */
diff --git a/platform/targets/Module17/platform.c b/platform/targets/Module17/platform.c
index c4ea1eda..2e6ec2f5 100644
--- a/platform/targets/Module17/platform.c
+++ b/platform/targets/Module17/platform.c
@@ -24,12 +24,16 @@
#include
#include
#include
+#include
#include
#include
#include
#include
#include
+
+I2C_STM32_DEVICE_DEFINE(i2c1, I2C1, NULL)
+
extern mod17Calib_t mod17CalData;
static hwInfo_t hwInfo =
@@ -58,6 +62,32 @@ void platform_init()
gpio_setMode(PTT_OUT, OUTPUT);
gpio_clearPin(PTT_OUT);
+ /*
+ * Check if external I2C1 pull-ups are present. If they are not,
+ * enable internal pull-ups and slow-down I2C1.
+ */
+ gpio_setMode(I2C1_SCL, INPUT_PULL_DOWN);
+ gpio_setMode(I2C1_SDA, INPUT_PULL_DOWN);
+
+ uint8_t i2cSpeed = I2C_SPEED_100kHz;
+ bool i2cPullups = gpio_readPin(I2C1_SCL)
+ & gpio_readPin(I2C1_SDA);
+
+ /* Set gpios to alternate function, connected to I2C peripheral */
+ if(i2cPullups == false)
+ {
+ gpio_setMode(I2C1_SCL, ALTERNATE_OD_PU | ALTERNATE_FUNC(4));
+ gpio_setMode(I2C1_SDA, ALTERNATE_OD_PU | ALTERNATE_FUNC(4));
+ i2cSpeed = I2C_SPEED_LOW;
+ }
+ else
+ {
+ gpio_setMode(I2C1_SCL, ALTERNATE_OD | ALTERNATE_FUNC(4));
+ gpio_setMode(I2C1_SDA, ALTERNATE_OD | ALTERNATE_FUNC(4));
+ }
+
+ i2c_init(&i2c1, i2cSpeed);
+
/* Set analog output for baseband signal to an idle level of 1.1V */
gpio_setMode(BASEBAND_TX, ANALOG);
RCC->APB1ENR |= RCC_APB1ENR_DACEN;
@@ -66,10 +96,9 @@ void platform_init()
nvm_init();
adc1_init();
- i2c_init();
- mcp4551_init(SOFTPOT_RX);
- mcp4551_init(SOFTPOT_TX);
audio_init();
+ mcp4551_init(&i2c1, SOFTPOT_RX);
+ mcp4551_init(&i2c1, SOFTPOT_TX);
/* Set defaults for calibration */
mod17CalData.tx_wiper = 0x080;