summaryrefslogtreecommitdiff
path: root/Core/Src/cs4272.c
blob: 9a7f0d1b63f1c537c80e27955248cd0a2ccc02a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 * cs4272.c
 *
 *  Created on: Aug 16, 2026
 *      Author: ozpv
 */

#include "i2c.h"
#include "cs4272.h"
#include "ringmod.h"

const struct RingModParams params = {
    0.40f,
    156.0f,
    6.90f,
    0.18f,
    true,
};

volatile int32_t rx_buffer[BUFFER_SIZE] __attribute__((section(".audio_buffers")));
volatile int32_t tx_buffer[BUFFER_SIZE] __attribute__((section(".audio_buffers")));
volatile float samples[BUFFER_SIZE] __attribute__((section(".sdram")));

const uint8_t CS4272_CONFIG[7] = {
        /* MODE CONTROL 1
           single speed i2s slave */
        0b00000001,
        /* DAC CONTROL
          Steep Interpolation Filter
          48 kHz de-emphasis
          Soft Ramp Up and Down and no polarity flip */
        0b01101100,
        /* DAC Volume & Mixing Control
          Channel B Volume = Channel A Volume
          Soft Ramp and Zero Cross
          a = L b = R
          stereo 0b01111001 */
        0b01111000,
        /* Channel A volume
           0 dB
           Binary Code Decimal Value Volume Setting
           0000000 0 0 dB
           0010100 20 -20 dB
           0101000 40 -40 dB
           0111100 60 -60 dB
           1011010 90 -90 dB */
        0b00000000,
        /* Channel B volume
           Muted for mono */
        0b10000000,
        /* ADC control
           I2S up to 24-bit data High Pass filter on
           bits 3:2 active high adc channel mute
           Channel B muted */
        0b00010100,
        /* MODE CONTROL 2
           power down OFF */
        0b00000010,
};

inline void int32_t_to_float(int32_t *in, float *out, const size_t range_min, const size_t range_max) {
    for (size_t i = range_min; i < range_max; ++i) {
        out[i] = ((float)(in[i] << 8)) / ((float)INT32_MAX);
    }
}

inline void float_to_int32_t(float *in, int32_t *out, const size_t range_min, const size_t range_max) {
    for (size_t i = range_min; i < range_max; ++i) {
        out[i] = ((int32_t)(in[i] * ((float)INT32_MAX))) >> 8;
    }
}

void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) {
    int32_t_to_float((int32_t *)rx_buffer, (float *)samples, 0, BUFFER_SIZE / 2);

    ringmod((float *)samples, 0, BUFFER_SIZE / 2, &params);

    float_to_int32_t((float *)samples, (int32_t *)tx_buffer, 0, BUFFER_SIZE / 2);
}

void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) {
    int32_t_to_float((int32_t *)rx_buffer, (float *)samples, BUFFER_SIZE / 2, BUFFER_SIZE);

    ringmod((float *)samples, BUFFER_SIZE / 2, BUFFER_SIZE, &params);

    float_to_int32_t((float *)samples, (int32_t *)tx_buffer, BUFFER_SIZE / 2, BUFFER_SIZE);
}


HAL_StatusTypeDef CS4272_ReadRegister(const uint8_t addr, uint8_t *data) {
    return HAL_I2C_Mem_Read(&hi2c4, CS4272_I2C_ADDR, addr, I2C_MEMADD_SIZE_8BIT, data, 1, HAL_MAX_DELAY);
}

HAL_StatusTypeDef CS4272_WriteRegister(const uint8_t addr, uint8_t data) {
    return HAL_I2C_Mem_Write(&hi2c4, CS4272_I2C_ADDR, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, HAL_MAX_DELAY);
}

void CS4272_Reset(void) {
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);

    HAL_Delay(10);

    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);

    HAL_Delay(10);
}

uint8_t CS4272_Init(void) {
    CS4272_Reset();

    if (HAL_I2C_IsDeviceReady(&hi2c4, CS4272_I2C_ADDR, 3, 1000) != HAL_OK) {
        return HAL_ERROR;
    }

    /* 5.2.1 Recommended Power-Up Sequence
       power down mode and control port enable */
    if (CS4272_WriteRegister(MODE_CONTROL_2, 0x03) != HAL_OK) {
        return HAL_ERROR;
    }

    /* check if device ID is correct */
    uint8_t id = 0;
    if (CS4272_ReadRegister(CHIP_ID, &id) != HAL_OK) {
        return HAL_ERROR;
    }

    if ((id >> 4) != CS4272_CHIP_ID) {
        return 2;
    }

    /* Configure */
    uint8_t cfg = 0;
    for (size_t i = MODE_CONTROL_1; i < CHIP_ID; ++i) {
        if (CS4272_WriteRegister(i, CS4272_CONFIG[i - 1]) != HAL_OK) {
            return HAL_ERROR;
        }

        if (CS4272_ReadRegister(i, &cfg) != HAL_OK) {
            return HAL_ERROR;
        }

        if (cfg != CS4272_CONFIG[i - 1]) {
            return 2;
        }
    }

    return HAL_OK;
}