kopia lustrzana https://github.com/OpenRTX/OpenRTX
Module17: use hardware I2C for MCP4551
rodzic
b196ce9cbc
commit
7052dbcf8b
|
@ -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': ''}
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <datatypes.h>
|
||||
#include <peripherals/i2c.h>
|
||||
|
||||
#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
|
||||
}
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#include <peripherals/gpio.h>
|
||||
#include <interfaces/delays.h>
|
||||
#include <hwconfig.h>
|
||||
#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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -22,9 +22,12 @@
|
|||
#ifndef HWCONFIG_H
|
||||
#define HWCONFIG_H
|
||||
|
||||
#include <peripherals/i2c.h>
|
||||
#include <stm32f4xx.h>
|
||||
#include "pinmap.h"
|
||||
|
||||
extern const struct i2cDevice i2c1;
|
||||
|
||||
/* Screen dimensions */
|
||||
#define CONFIG_SCREEN_WIDTH 128
|
||||
#define CONFIG_SCREEN_HEIGHT 64
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -24,12 +24,16 @@
|
|||
#include <interfaces/nvmem.h>
|
||||
#include <interfaces/audio.h>
|
||||
#include <peripherals/gpio.h>
|
||||
#include <drivers/i2c_stm32.h>
|
||||
#include <calibInfo_Mod17.h>
|
||||
#include <ADC1_Mod17.h>
|
||||
#include <backlight.h>
|
||||
#include <hwconfig.h>
|
||||
#include <MCP4551.h>
|
||||
|
||||
|
||||
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;
|
||||
|
|
Ładowanie…
Reference in New Issue