From ff926fc784b21563729b5161d502d143341308b2 Mon Sep 17 00:00:00 2001 From: cfif Date: Wed, 4 Dec 2024 13:10:49 +0300 Subject: [PATCH] Init --- Inc/max9860.h | 126 +++++++++++++++++++++++++++++ Inc/max9860_enums.h | 73 +++++++++++++++++ Inc/max9860_regs.h | 49 ++++++++++++ Src/audio_codec.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ modular.json | 17 ++++ 5 files changed, 455 insertions(+) create mode 100644 Inc/max9860.h create mode 100644 Inc/max9860_enums.h create mode 100644 Inc/max9860_regs.h create mode 100644 Src/audio_codec.c create mode 100644 modular.json diff --git a/Inc/max9860.h b/Inc/max9860.h new file mode 100644 index 0000000..9a33fda --- /dev/null +++ b/Inc/max9860.h @@ -0,0 +1,126 @@ +// +// Created by zemon on 24.06.2021. +// + +#ifndef MAX_9860_H +#define MAX_9860_H + +#include "I2cIO.h" +#include "stdbool.h" +#include "max9860_enums.h" + +#define MAX9860_TOTAL_REG_COUNT 0x11 + +typedef struct { + MAX9860_MCLK_TO_PCLK_PrescalerMode MCLK_TO_PCLK_Prescaler; + MAX9860_IntegerClockMode IntegerClockMode; + bool EXACTLY_16KHZ; + bool PLL_Enable; //enable core clock as divided mclk + uint16_t LRCLK_Driver; //clock divider, depends on mclk and sample rate (lrclk) +} MAX9860_ClocksState; + + +typedef struct { + bool MasterMode; + bool LRCLK_Invert; + bool DAC_BCLK_Invert; + bool DAC_DelayMode; + bool SDOUT_HighImpedanceMode; + bool TDM_ModeSelect; + bool ADC_BCLK_Invert; + bool ADC_Delay_Mode; + bool StereoEnable; + uint8_t BCLK_Select; +} MAX9860_AudioInterfaceState; + + +typedef struct { + MAX9860_DigitalFilterType ADC_DigitalFilter; + MAX9860_DigitalFilterType DAC_DigitalFilter; +} MAX9860_DigitalFiltersState; + +//range from +3dB to -90dB +#define MAX9860_DAC_LEVEL_ADJUST__DB(DB_VALUE) (DB_VALUE>3?0:(DB_VALUE<-90?0xBC:(6-(DB_VALUE*2)))) + +//range from +3dB to -12dB +#define MAX9860_ADC_OUTPUT_LEVEL__DB(DB_VALUE) (DB_VALUE>3?0:(DB_VALUE<-12?0xF:(3-DB_VALUE))) + +#define MAX9860_DAC_GAIN__0 0b00 +#define MAX9860_DAC_GAIN__PLUS_6DB 0b01 +#define MAX9860_DAC_GAIN__PLUS_12DB 0b10 +#define MAX9860_DAC_GAIN__PLUS_18DB 0b11 + +#define MAX9860_SIDETONE_DISABLED 0b0 + +typedef struct { + uint8_t DAC_LevelAdjust; + uint8_t ADC_OutputLevelRight; + uint8_t ADC_OutputLevelLeft; + uint8_t DAC_Gain; + uint8_t Sidetone; +} MAX9860_DigitalLevelControlState; + +#define MAX9860_MIC_PREAMP_GAIN__DISABLED 0b00 +#define MAX9860_MIC_PREAMP_GAIN__0 0b01 +#define MAX9860_MIC_PREAMP_GAIN__PLUS_20 0b10 +#define MAX9860_MIC_PREAMP_GAIN__PLUS_30 0b11 + +//range form 0 to +20dB +#define MAX9860_MIC_PROGRAMMABLE_GAIN_PLUS_DB(DB_VALUE) (DB_VALUE<0?0x20:(DB_VALUE>20?0:(20-DB_VALUE))) + +typedef struct { + uint8_t MicrophonePreampGain; + uint8_t MicrophoneProgrammableGain; +} MAX9860_MicrophoneInputState; + + +typedef struct { + MAX9860_NoiseGateSignalSource NoiseGateSource; + MAX9860_AutomaticGainControlReleaseTime ReleaseTime; + MAX9860_AutomaticGainControlAttackTime AttackTime; + MAX9860_AutomaticGainControlHoldTime HoldTime; + + uint8_t NoiseGateThreshold; + uint8_t AutomaticGainControlThreshold; + +} MAX9860_AutomaticGainControlAndNoiseGateState; + +typedef struct { + bool FullPowerOn; + bool DAC_Enabled; + bool ADC_EnabledLeft; + bool ADC_EnabledRight; +} MAX9860_PowerManagementState; + + +typedef struct { + MAX9860_DigitalFiltersState filters; + MAX9860_DigitalLevelControlState levelControl; + MAX9860_MicrophoneInputState microphoneGains; + MAX9860_AutomaticGainControlAndNoiseGateState autoGainAndNoiseGate; +} MAX9860_ComplexAudioConfig; + + +uint16_t xAudioCodecDebugGetRAW(tI2cIO *i2c, uint8_t *raw); + +uint16_t xAudioCodecDebugSetRAW(tI2cIO *i2c, uint8_t *raw); + +uint16_t xAudioCodecReadStatus(tI2cIO *i2c, uint8_t statuses[3]); + +bool xAudioCodecSetClock(tI2cIO *i2c, MAX9860_ClocksState clocksState); + +bool xAudioCodecSetInterface(tI2cIO *i2c, MAX9860_AudioInterfaceState interface); + +bool xAudioCodecSetDigitalFilters(tI2cIO *i2c, MAX9860_DigitalFiltersState filters); + +bool xAudioCodecSetDigitalLevelControls(tI2cIO *i2c, MAX9860_DigitalLevelControlState levels); + +bool xAudioCodecSetMicrophoneInput(tI2cIO *i2c, MAX9860_MicrophoneInputState micro); + +bool xAudioCodecSetAutomaticGainControlAndNoiseGate( + tI2cIO *i2c, MAX9860_AutomaticGainControlAndNoiseGateState values +); + +bool xAudioCodecSetPowerManagement(tI2cIO *i2c, MAX9860_PowerManagementState values); + +#endif //MAX_9860_H diff --git a/Inc/max9860_enums.h b/Inc/max9860_enums.h new file mode 100644 index 0000000..f463a7f --- /dev/null +++ b/Inc/max9860_enums.h @@ -0,0 +1,73 @@ +// +// Created by zemon on 25.06.2021. +// + +#ifndef STM_MAIN_WORKSPACE_MAX9860_ENUMS_H +#define STM_MAIN_WORKSPACE_MAX9860_ENUMS_H + + +typedef enum { + MAX9860_PRESCALER_DISABLE_CLOCK = 0b00, + MAX9860_PRESCALER_MCLK_10_TO_20_MHZ = 0b01, + MAX9860_PRESCALER_MCLK_20_TO_40_MHZ = 0b10, + MAX9860_PRESCALER_MCLK_MORE_40_MHZ = 0b11, +} MAX9860_MCLK_TO_PCLK_PrescalerMode; + +typedef enum { + MAX9860_ICM_NORMAL = 0b00, + MAX9860_ICM_PCLK_IS_12MHZ = 0b01, + MAX9860_ICM_PCLK_IS_13MHZ = 0b10, + MAX9860_ICM_PCLK_IS_19_2MHZ = 0b11, +} MAX9860_IntegerClockMode; + + + +typedef enum { + MAX9860_DIGITAL_FILTER_DISABLED = 0x0, + MAX9860_DIGITAL_FILTER_ELLIPTICAL_16KHZ = 0x1, + MAX9860_DIGITAL_FILTER_BUTTERWORTH_16KHZ = 0x2, + MAX9860_DIGITAL_FILTER_ELLIPTICAL_8KHZ = 0x3, + MAX9860_DIGITAL_FILTER_BUTTERWORTH_8KHZ = 0x4, + MAX9860_DIGITAL_FILTER_BUTTERWORTH_48KHZ = 0x5, +} MAX9860_DigitalFilterType; + + +typedef enum { + MAX9860_NOISE_GATE_SOURCE_LEFT_ONLY = 0x0, + MAX9860_NOISE_GATE_SOURCE_SUM_BOTH = 0x1, +} MAX9860_NoiseGateSignalSource; + + +typedef enum { + MAX9860_AUTOMATIC_GAIN_CONTROL_RELEASE_TIME_78_MS = 0x000, + MAX9860_AUTOMATIC_GAIN_CONTROL_RELEASE_TIME_156_MS = 0x001, + MAX9860_AUTOMATIC_GAIN_CONTROL_RELEASE_TIME_312_MS = 0x010, + MAX9860_AUTOMATIC_GAIN_CONTROL_RELEASE_TIME_652_MS = 0x011, + MAX9860_AUTOMATIC_GAIN_CONTROL_RELEASE_TIME_1250_MS = 0x100, + MAX9860_AUTOMATIC_GAIN_CONTROL_RELEASE_TIME_2500_MS = 0x101, + MAX9860_AUTOMATIC_GAIN_CONTROL_RELEASE_TIME_5_S = 0x110, + MAX9860_AUTOMATIC_GAIN_CONTROL_RELEASE_TIME_10_S = 0x111, +} MAX9860_AutomaticGainControlReleaseTime; + +typedef enum { + MAX9860_AUTOMATIC_GAIN_CONTROL_ATTACK_TIME_3_MS = 0x00, + MAX9860_AUTOMATIC_GAIN_CONTROL_ATTACK_TIME_12_MS = 0x01, + MAX9860_AUTOMATIC_GAIN_CONTROL_ATTACK_TIME_50_MS = 0x10, + MAX9860_AUTOMATIC_GAIN_CONTROL_ATTACK_TIME_200_MS = 0x11, +} MAX9860_AutomaticGainControlAttackTime; + +typedef enum { + MAX9860_AUTOMATIC_GAIN_CONTROL_DISABLED = 0x00, + MAX9860_AUTOMATIC_GAIN_CONTROL_HOLD_TIME_50_MS = 0x01, + MAX9860_AUTOMATIC_GAIN_CONTROL_HOLD_TIME_100_MS = 0x10, + MAX9860_AUTOMATIC_GAIN_CONTROL_HOLD_TIME_400_MS = 0x11, +} MAX9860_AutomaticGainControlHoldTime; + + +typedef enum{ + MAX9860_FULL_SHUTDOWN = 0x0, + MAX9860_POWER_ON = 0x1, +}MAX9860_SoftwareShutdownValue; + + +#endif //STM_MAIN_WORKSPACE_MAX9860_ENUMS_H diff --git a/Inc/max9860_regs.h b/Inc/max9860_regs.h new file mode 100644 index 0000000..bc4c6f9 --- /dev/null +++ b/Inc/max9860_regs.h @@ -0,0 +1,49 @@ +// +// Created by zemon on 24.06.2021. +// + +#ifndef STM_MAIN_WORKSPACE_MAX9860_REGS_H +#define STM_MAIN_WORKSPACE_MAX9860_REGS_H + +#define MAX9860_ADDRESS_READ 0x21 +#define MAX9860_ADDRESS_WRITE 0x20 +#define MAX9860_IO_TIMEOUT 1000 + + +//STATUS/INTERRUPT +#define MAX9860_REG_STATUS_INTERRUPTS_VALUES 0x00 +#define MAX9860_REG_STATUS_NOISE_GAIN 0x01 +#define MAX9860_REG_STATUS_INTERRUPTS_ENABLED 0x02 + +//CLOCK CONTROL +#define MAX9860_REG_SYSTEM_CLOCK 0x03 +#define MAX9860_REG_STEREO_AUDIO_CLOCK_CONTROL_HIGH 0x04 +#define MAX9860_REG_STEREO_AUDIO_CLOCK_CONTROL_LOW 0x05 + +//DIGITAL AUDIO INTERFACE TODO REDUCE UNUSED +#define MAX9860_REG_INTERFACE 0x06 +#define MAX9860_REG_INTERFACE_FIRST 0x06 +#define MAX9860_REG_INTERFACE_SECOND 0x07 + +//DIGITAL FILTERING +#define MAX9860_REG_VOICE_FILTERING 0x08 + +//DIGITAL LEVEL CONTROL +#define MAX9860_REG_DAC_ATTENUATION 0x09 //DAC - digital analog converter +#define MAX9860_REG_ADC_OUTPUT_LEVEL 0x0A //ADC - analog digital converter +#define MAX9860_REG_DAC_GAIN_AND_SIDETONE 0x0B + +//MICROPHONE LEVEL CONTROL +#define MAX9860_REG_MICROPHONE_GAIN 0x0C + +//MICROPHONE AUTOMATIC GAIN CONTROL +#define MAX9860_REG_MICROPHONE_AGC 0x0E //AGC -automatic gain control +#define MAX9860_REG_MICROPHONE_AGC_AND_NOISE_GATE 0x0F + +//POWER MANAGEMENT +#define MAX9860_REG_SYSTEM_SHUTDOWN 0x10 + + + + +#endif //STM_MAIN_WORKSPACE_MAX9860_REGS_H diff --git a/Src/audio_codec.c b/Src/audio_codec.c new file mode 100644 index 0000000..f4a6f40 --- /dev/null +++ b/Src/audio_codec.c @@ -0,0 +1,190 @@ +// +// Created by zemon on 24.06.2021. +// + +#include +#include "max9860.h" +#include "max9860_regs.h" + +bool xAudioCodecSetClock(tI2cIO *i2c, MAX9860_ClocksState clocksState) { + + uint8_t I2C_Out[4] = {0}; + I2C_Out[0] = MAX9860_REG_SYSTEM_CLOCK; + I2C_Out[1] = 0x00 | + ((clocksState.MCLK_TO_PCLK_Prescaler & 0b11) << 4) | + ((clocksState.IntegerClockMode & 0b11) << 1) | + ((clocksState.EXACTLY_16KHZ & 0b1) << 0); + + I2C_Out[2] = 0x00 | + ((clocksState.PLL_Enable & 0b1) << 7) | + (((uint8_t) (clocksState.LRCLK_Driver >> 8)) & 0b01111111); + + I2C_Out[3] = ((uint8_t) (clocksState.LRCLK_Driver & 0xFF)); + + return I2cWrite(i2c, MAX9860_ADDRESS_WRITE, I2C_Out, 4, MAX9860_IO_TIMEOUT) == 4; +} + + +bool xAudioCodecSetInterface(tI2cIO *i2c, MAX9860_AudioInterfaceState interface) { + + uint8_t I2C_Out[3] = {0}; + I2C_Out[0] = MAX9860_REG_INTERFACE; + I2C_Out[1] = 0x00 | + ((interface.MasterMode & 0b1) << 7) | + ((interface.LRCLK_Invert & 0b1) << 6) | + ((interface.DAC_BCLK_Invert & 0b1) << 5) | + ((interface.DAC_DelayMode & 0b1) << 4) | + ((interface.SDOUT_HighImpedanceMode & 0b1) << 3) | + ((interface.TDM_ModeSelect & 0b1) << 2); + + + I2C_Out[2] = 0x00 | + ((interface.ADC_BCLK_Invert & 0b1) << 5) | + ((interface.ADC_Delay_Mode & 0b1) << 4) | + ((interface.StereoEnable & 0b1) << 3) | + ((interface.BCLK_Select & 0b111) << 0); + + return I2cWrite(i2c, MAX9860_ADDRESS_WRITE, I2C_Out, 3, MAX9860_IO_TIMEOUT) == 3; +} + + +bool xAudioCodecSetDigitalFilters(tI2cIO *i2c, MAX9860_DigitalFiltersState filters) { + + uint8_t I2C_Out[2] = {0}; + I2C_Out[0] = MAX9860_REG_VOICE_FILTERING; + I2C_Out[1] = 0x00 | + ((filters.ADC_DigitalFilter & 0b1111) << 4) | + ((filters.DAC_DigitalFilter & 0b1111) << 0); + + return I2cWrite(i2c, MAX9860_ADDRESS_WRITE, I2C_Out, 2, MAX9860_IO_TIMEOUT) == 2; +} + + +bool xAudioCodecSetDigitalLevelControls(tI2cIO *i2c, MAX9860_DigitalLevelControlState levels) { + + uint8_t I2C_Out[4] = {0}; + I2C_Out[0] = MAX9860_REG_DAC_ATTENUATION; + I2C_Out[1] = levels.DAC_LevelAdjust; + + I2C_Out[2] = 0x00 | + ((levels.ADC_OutputLevelRight & 0b1111) << 4) | + ((levels.ADC_OutputLevelLeft & 0b1111) << 0); + + I2C_Out[3] = 0x00 | + ((levels.DAC_Gain & 0b11) << 5) | + ((levels.Sidetone & 0b11111) << 0); + + return I2cWrite(i2c, MAX9860_ADDRESS_WRITE, I2C_Out, 4, MAX9860_IO_TIMEOUT) == 4; +} + + +bool xAudioCodecSetMicrophoneInput(tI2cIO *i2c, MAX9860_MicrophoneInputState micro) { + + uint8_t I2C_Out[2] = {0}; + I2C_Out[0] = MAX9860_REG_MICROPHONE_GAIN; + + I2C_Out[1] = 0x00 | + ((micro.MicrophonePreampGain & 0b11) << 5) | + ((micro.MicrophoneProgrammableGain & 0b11111) << 0); + + return I2cWrite(i2c, MAX9860_ADDRESS_WRITE, I2C_Out, 2, MAX9860_IO_TIMEOUT) == 2; +} + + +bool xAudioCodecSetAutomaticGainControlAndNoiseGate( + tI2cIO *i2c, + MAX9860_AutomaticGainControlAndNoiseGateState values +) { + + uint8_t I2C_Out[3] = {0}; + I2C_Out[0] = MAX9860_REG_MICROPHONE_AGC; + + I2C_Out[1] = 0x00 | + ((values.NoiseGateSource & 0b1) << 7) | + ((values.ReleaseTime & 0b111) << 4) | + ((values.AttackTime & 0b11) << 2) | + ((values.HoldTime & 0b11) << 0); + + I2C_Out[2] = 0x00 | + ((values.NoiseGateThreshold & 0b1111) << 4) | + ((values.AutomaticGainControlThreshold & 0b1111) << 0); + + return I2cWrite(i2c, MAX9860_ADDRESS_WRITE, I2C_Out, 3, MAX9860_IO_TIMEOUT) == 3; +} + + +bool xAudioCodecSetPowerManagement(tI2cIO *i2c, MAX9860_PowerManagementState values) { + + uint8_t I2C_Out[3] = {0}; + I2C_Out[0] = MAX9860_REG_SYSTEM_SHUTDOWN; + + I2C_Out[1] = 0x00 | + ((values.FullPowerOn & 0b1) << 7) | + ((values.DAC_Enabled & 0b1) << 3) | + ((values.ADC_EnabledLeft & 0b1) << 1) | + ((values.ADC_EnabledRight & 0b1) << 0); + + return I2cWrite(i2c, MAX9860_ADDRESS_WRITE, I2C_Out, 2, MAX9860_IO_TIMEOUT) == 2; +} + +uint16_t xAudioCodecDebugGetRAW(tI2cIO *i2c, uint8_t *raw) { + return I2cRead(i2c, MAX9860_ADDRESS_READ, raw, MAX9860_TOTAL_REG_COUNT, MAX9860_IO_TIMEOUT); +} + + +uint16_t xAudioCodecDebugSetRAW(tI2cIO *i2c, uint8_t *raw) { + return I2cRead(i2c, MAX9860_ADDRESS_WRITE, raw, MAX9860_TOTAL_REG_COUNT, MAX9860_IO_TIMEOUT); +} + + +uint16_t xAudioCodecReadStatus(tI2cIO *i2c, uint8_t statuses[3]) { + uint8_t I2C_Out[4] = {0}; + + I2C_Out[0] = MAX9860_REG_STATUS_INTERRUPTS_VALUES; + + uint16_t write = I2cWrite(i2c, MAX9860_ADDRESS_WRITE, I2C_Out, 1, MAX9860_IO_TIMEOUT); + + uint16_t reed = I2cRead(i2c, MAX9860_ADDRESS_READ, I2C_Out + 1, 3, MAX9860_IO_TIMEOUT); + + memcpy(statuses, I2C_Out + 1, reed); + return reed; +} + + + + + +//void PowerSuportInitAudioDevice(PowerSupportEnvironment* env){ +// HAL_StatusTypeDef error; +// +// uint8_t I2C_Out[16] = {0}; +// uint8_t I2C_In[17] = {0}; +// +// // 0 1 2 3 4 5 6 7 8 9 0A 0B 0C 0D 0E 0F 10 +// // 0x00 0x00 0x00 0x10 0x1E 0x3F 0x24 0x00 0x00 0x06 0x33 0x00 0x4A 0x00 0x00 0x00 0x8A +// // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 +// I2C_Out[0] = 0x03; //Address +// I2C_Out[1] = 0x10; //0x03 System Clock +// I2C_Out[2] = 0x10; //0x04 Stereo Audio Clock / Control High +// I2C_Out[3] = 0x62; //0x05 Stereo Audio Clock / Control Low +// I2C_Out[4] = 0x40; //0x06 Interface +// I2C_Out[5] = 0x00; //0x07 Interface +// I2C_Out[6] = 0x00; //0x08 Voice Filter +// I2C_Out[7] = 0x08; //0x09 DAC Attenuation DAC Level Adjust -10:0x1A +// I2C_Out[8] = 0x33; //0x0A ADC Output Levels DA Level 4:[left -10:0xD][right -10:0xD] +// I2C_Out[9] = 0x00; //0x0B DAC Gain and Sidetone 0 2:[DVG 00] 5:[DVST -10:0x00] +// I2C_Out[10] = 0x4A; //0x0C Microphone Gain -- 0 2:[MicPreAmp 00] 5:[Mic PGA 0x14] +// I2C_Out[11] = 0x00; //0x0D Reserved +// I2C_Out[12] = 0x00; //0x0E Microphone AGC +// I2C_Out[13] = 0x00; //0x0F Noise Gate, Microphone AGC +// I2C_Out[14] = 0x8A; //0x10 System Shutdown +// +// error = HAL_I2C_Master_Transmit(env->audioI2c, 0x20, I2C_Out, 15, 500); +// +// I2C_Out[0] = 0x00; +// error = HAL_I2C_Master_Receive(env->audioI2c, 0x21, I2C_In, 17, 500); +//} + + + + diff --git a/modular.json b/modular.json new file mode 100644 index 0000000..c8bc16a --- /dev/null +++ b/modular.json @@ -0,0 +1,17 @@ +{ + "dep": [ + { + "type": "git", + "provider": "NAVIGATOR_UVEOS_NATION_TELIT", + "repo": "I2cPortInterface" + } + ], + "cmake": { + "inc_dirs": [ + "Inc" + ], + "srcs": [ + "Src/**.c" + ] + } +} \ No newline at end of file