Codec confiuguration implementation.
This commit is contained in:
parent
9beeb23c89
commit
eae22f28a8
|
@ -56,12 +56,12 @@ static const default_configuration default_config = {
|
||||||
.f4 = { HIGHSHELF, {0}, 8400, 2, 0.7 },
|
.f4 = { HIGHSHELF, {0}, 8400, 2, 0.7 },
|
||||||
.f5 = { PEAKING, {0}, 4800, 3, 5 }
|
.f5 = { PEAKING, {0}, 4800, 3, 5 }
|
||||||
},
|
},
|
||||||
.preprocessing = { .header = { PREPROCESSING_CONFIGURATION, sizeof(default_config.preprocessing) }, -0.1f, false, {0} }
|
.preprocessing = { .header = { PREPROCESSING_CONFIGURATION, sizeof(default_config.preprocessing) }, -0.2f, false, {0} }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Grab the last 4k page of flash for our configuration strutures.
|
// Grab the last 4k page of flash for our configuration strutures.
|
||||||
#ifndef TEST_TARGET
|
#ifndef TEST_TARGET
|
||||||
static const size_t USER_CONFIGURATION_OFFSET = PICO_FLASH_SIZE_BYTES - 0x1000;
|
static const size_t USER_CONFIGURATION_OFFSET = PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE;
|
||||||
const uint8_t *user_configuration = (const uint8_t *) (XIP_BASE + USER_CONFIGURATION_OFFSET);
|
const uint8_t *user_configuration = (const uint8_t *) (XIP_BASE + USER_CONFIGURATION_OFFSET);
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
|
@ -74,8 +74,6 @@ static uint8_t inactive_working_configuration = 0;
|
||||||
static uint8_t result_buffer[256] = { U16_TO_U8S_LE(NOK), U16_TO_U8S_LE(4) };
|
static uint8_t result_buffer[256] = { U16_TO_U8S_LE(NOK), U16_TO_U8S_LE(4) };
|
||||||
|
|
||||||
static bool reload_config = false;
|
static bool reload_config = false;
|
||||||
static bool save_config = false;
|
|
||||||
static bool factory_reset = false;
|
|
||||||
static uint16_t write_offset = 0;
|
static uint16_t write_offset = 0;
|
||||||
static uint16_t read_offset = 0;
|
static uint16_t read_offset = 0;
|
||||||
|
|
||||||
|
@ -208,13 +206,20 @@ bool validate_configuration(tlv_header *config) {
|
||||||
break;
|
break;
|
||||||
case PREPROCESSING_CONFIGURATION: {
|
case PREPROCESSING_CONFIGURATION: {
|
||||||
preprocessing_configuration_tlv* preprocessing_config = (preprocessing_configuration_tlv*) tlv;
|
preprocessing_configuration_tlv* preprocessing_config = (preprocessing_configuration_tlv*) tlv;
|
||||||
//printf("Preproc %0.2f %d\n", preprocessing_config->preamp, preprocessing_config->reverse_stereo);
|
|
||||||
if (tlv->length != sizeof(preprocessing_configuration_tlv)) {
|
if (tlv->length != sizeof(preprocessing_configuration_tlv)) {
|
||||||
printf("Preprocessing size missmatch: %u != %zu\n", tlv->length, sizeof(preprocessing_configuration_tlv));
|
printf("Preprocessing size missmatch: %u != %zu\n", tlv->length, sizeof(preprocessing_configuration_tlv));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PCM3060_CONFIGURATION: {
|
||||||
|
pcm3060_configuration_tlv* pcm3060_config = (pcm3060_configuration_tlv*) tlv;
|
||||||
|
if (tlv->length != sizeof(pcm3060_configuration_tlv)) {
|
||||||
|
printf("PCM3060 config size missmatch: %u != %zu\n", tlv->length, sizeof(pcm3060_configuration_tlv));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// Unknown TLVs are not invalid, just ignored.
|
// Unknown TLVs are not invalid, just ignored.
|
||||||
break;
|
break;
|
||||||
|
@ -253,6 +258,14 @@ bool apply_configuration(tlv_header *config) {
|
||||||
preprocessing.reverse_stereo = preprocessing_config->reverse_stereo;
|
preprocessing.reverse_stereo = preprocessing_config->reverse_stereo;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PCM3060_CONFIGURATION: {
|
||||||
|
pcm3060_configuration_tlv* pcm3060_config = (pcm3060_configuration_tlv*) tlv;
|
||||||
|
audio_state.oversampling = pcm3060_config->oversampling;
|
||||||
|
audio_state.phase = pcm3060_config->phase;
|
||||||
|
audio_state.rolloff = pcm3060_config->rolloff;
|
||||||
|
audio_state.de_emphasis = pcm3060_config->de_emphasis;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -275,15 +288,16 @@ void load_config() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TEST_TARGET
|
#ifndef TEST_TARGET
|
||||||
// Must be in RAM
|
|
||||||
uint8_t flash_buffer[FLASH_PAGE_SIZE];
|
|
||||||
bool __no_inline_not_in_flash_func(save_configuration)() {
|
bool __no_inline_not_in_flash_func(save_configuration)() {
|
||||||
const uint8_t active_configuration = inactive_working_configuration ? 0 : 1;
|
const uint8_t active_configuration = inactive_working_configuration ? 0 : 1;
|
||||||
tlv_header* config = (tlv_header*) working_configuration[active_configuration];
|
tlv_header* config = (tlv_header*) working_configuration[active_configuration];
|
||||||
|
|
||||||
if (validate_configuration(config)) {
|
if (validate_configuration(config)) {
|
||||||
|
power_down_dac();
|
||||||
|
|
||||||
const size_t config_length = config->length - (size_t)((size_t)config->value - (size_t)config);
|
const size_t config_length = config->length - (size_t)((size_t)config->value - (size_t)config);
|
||||||
// Write data to flash
|
// Write data to flash
|
||||||
|
uint8_t flash_buffer[FLASH_PAGE_SIZE];
|
||||||
flash_header_tlv* flash_header = (flash_header_tlv*) flash_buffer;
|
flash_header_tlv* flash_header = (flash_header_tlv*) flash_buffer;
|
||||||
flash_header->header.type = FLASH_HEADER;
|
flash_header->header.type = FLASH_HEADER;
|
||||||
flash_header->header.length = sizeof(flash_header) + config_length;
|
flash_header->header.length = sizeof(flash_header) + config_length;
|
||||||
|
@ -291,8 +305,6 @@ bool __no_inline_not_in_flash_func(save_configuration)() {
|
||||||
flash_header->version = CONFIG_VERSION;
|
flash_header->version = CONFIG_VERSION;
|
||||||
memcpy((void*)(flash_header->tlvs), config->value, config_length);
|
memcpy((void*)(flash_header->tlvs), config->value, config_length);
|
||||||
|
|
||||||
power_down_dac();
|
|
||||||
|
|
||||||
uint32_t ints = save_and_disable_interrupts();
|
uint32_t ints = save_and_disable_interrupts();
|
||||||
flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_SIZE);
|
flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_SIZE);
|
||||||
flash_range_program(USER_CONFIGURATION_OFFSET, flash_buffer, FLASH_PAGE_SIZE);
|
flash_range_program(USER_CONFIGURATION_OFFSET, flash_buffer, FLASH_PAGE_SIZE);
|
||||||
|
@ -305,6 +317,15 @@ bool __no_inline_not_in_flash_func(save_configuration)() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool __no_inline_not_in_flash_func(factory_reset)() {
|
||||||
|
power_down_dac();
|
||||||
|
uint32_t ints = save_and_disable_interrupts();
|
||||||
|
flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_SIZE);
|
||||||
|
restore_interrupts(ints);
|
||||||
|
power_up_dac();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool process_cmd(tlv_header* cmd) {
|
bool process_cmd(tlv_header* cmd) {
|
||||||
tlv_header* result = ((tlv_header*) result_buffer);
|
tlv_header* result = ((tlv_header*) result_buffer);
|
||||||
switch (cmd->type) {
|
switch (cmd->type) {
|
||||||
|
@ -318,8 +339,7 @@ bool process_cmd(tlv_header* cmd) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SAVE_CONFIGURATION: {
|
case SAVE_CONFIGURATION: {
|
||||||
if (cmd->length == 4) {
|
if (cmd->length == 4 && save_configuration()) {
|
||||||
save_config = true;
|
|
||||||
result->type = OK;
|
result->type = OK;
|
||||||
result->length = 4;
|
result->length = 4;
|
||||||
return true;
|
return true;
|
||||||
|
@ -327,8 +347,7 @@ bool process_cmd(tlv_header* cmd) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FACTORY_RESET: {
|
case FACTORY_RESET: {
|
||||||
if (cmd->length == 4) {
|
if (cmd->length == 4 && factory_reset()) {
|
||||||
factory_reset = true;
|
|
||||||
flash_header_tlv flash_header = { 0 };
|
flash_header_tlv flash_header = { 0 };
|
||||||
result->type = OK;
|
result->type = OK;
|
||||||
result->length = 4;
|
result->length = 4;
|
||||||
|
@ -411,21 +430,6 @@ void config_in_packet(struct usb_endpoint *ep) {
|
||||||
usb_packet_done(ep);
|
usb_packet_done(ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_core0_config() {
|
|
||||||
if (save_config) {
|
|
||||||
save_config = false;
|
|
||||||
save_configuration();
|
|
||||||
}
|
|
||||||
if (factory_reset) {
|
|
||||||
factory_reset = false;
|
|
||||||
power_down_dac();
|
|
||||||
uint32_t ints = save_and_disable_interrupts();
|
|
||||||
flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_SIZE);
|
|
||||||
restore_interrupts(ints);
|
|
||||||
power_up_dac();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void apply_core1_config() {
|
void apply_core1_config() {
|
||||||
if (reload_config) {
|
if (reload_config) {
|
||||||
reload_config = false;
|
reload_config = false;
|
||||||
|
|
|
@ -41,7 +41,6 @@ struct usb_endpoint;
|
||||||
void config_in_packet(struct usb_endpoint *ep);
|
void config_in_packet(struct usb_endpoint *ep);
|
||||||
void config_out_packet(struct usb_endpoint *ep);
|
void config_out_packet(struct usb_endpoint *ep);
|
||||||
extern void load_config();
|
extern void load_config();
|
||||||
extern void apply_core0_config();
|
|
||||||
extern void apply_core1_config();
|
extern void apply_core1_config();
|
||||||
|
|
||||||
#endif // CONFIGURATION_MANAGER_H
|
#endif // CONFIGURATION_MANAGER_H
|
|
@ -96,6 +96,15 @@ typedef struct __attribute__((__packed__)) _filter_configuration_tlv {
|
||||||
const uint8_t filters[];
|
const uint8_t filters[];
|
||||||
} filter_configuration_tlv;
|
} filter_configuration_tlv;
|
||||||
|
|
||||||
|
typedef struct __attribute__((__packed__)) _pcm3060_configuration_tlv {
|
||||||
|
tlv_header header;
|
||||||
|
const uint8_t oversampling;
|
||||||
|
const uint8_t phase;
|
||||||
|
const uint8_t rolloff;
|
||||||
|
const uint8_t de_emphasis;
|
||||||
|
} pcm3060_configuration_tlv;
|
||||||
|
|
||||||
|
|
||||||
typedef struct __attribute__((__packed__)) _version_status_tlv {
|
typedef struct __attribute__((__packed__)) _version_status_tlv {
|
||||||
tlv_header header;
|
tlv_header header;
|
||||||
uint16_t current_version;
|
uint16_t current_version;
|
||||||
|
|
|
@ -51,6 +51,7 @@ static uint8_t *userbuf;
|
||||||
|
|
||||||
audio_state_config audio_state = {
|
audio_state_config audio_state = {
|
||||||
.freq = 48000,
|
.freq = 48000,
|
||||||
|
.de_emphasis_frequency = 0x1, // 48khz
|
||||||
};
|
};
|
||||||
|
|
||||||
preprocessing_config preprocessing = {
|
preprocessing_config preprocessing = {
|
||||||
|
@ -97,8 +98,6 @@ static void _as_audio_packet(struct usb_endpoint *ep) {
|
||||||
int32_t *out = (int32_t *) userbuf;
|
int32_t *out = (int32_t *) userbuf;
|
||||||
int samples = usb_buffer->data_len / 2;
|
int samples = usb_buffer->data_len / 2;
|
||||||
|
|
||||||
// Update filters if required
|
|
||||||
apply_core0_config();
|
|
||||||
|
|
||||||
if (preprocessing.reverse_stereo) {
|
if (preprocessing.reverse_stereo) {
|
||||||
for (int i = 0; i < samples; i+=2) {
|
for (int i = 0; i < samples; i+=2) {
|
||||||
|
@ -152,6 +151,15 @@ static void update_volume()
|
||||||
|
|
||||||
audio_state._volume = audio_state._target_volume;
|
audio_state._volume = audio_state._target_volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (audio_state.pcm3060_registers != audio_state._target_pcm3060_registers) {
|
||||||
|
uint8_t buf[3];
|
||||||
|
buf[0] = 68; // register addr
|
||||||
|
buf[1] = audio_state.target_pcm3060_registers[0]; // Reg 68
|
||||||
|
buf[2] = audio_state.target_pcm3060_registers[1]; // Reg 69
|
||||||
|
i2c_write_blocking(i2c0, PCM_I2C_ADDR, buf, 3, false);
|
||||||
|
audio_state.pcm3060_registers = audio_state._target_pcm3060_registers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void core1_entry() {
|
void core1_entry() {
|
||||||
|
@ -589,7 +597,7 @@ static bool do_get_current(struct usb_setup_packet *setup) {
|
||||||
if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
|
if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
|
||||||
switch (setup->wValue >> 8u) {
|
switch (setup->wValue >> 8u) {
|
||||||
case 1: { // mute
|
case 1: { // mute
|
||||||
usb_start_tiny_control_in_transfer(audio_state.mute, 1);
|
usb_start_tiny_control_in_transfer((audio_state.mute != 0), 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case 2: { // volume
|
case 2: { // volume
|
||||||
|
@ -705,11 +713,7 @@ static void audio_cmd_packet(struct usb_endpoint *ep) {
|
||||||
if (audio_control_cmd_t.type == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
|
if (audio_control_cmd_t.type == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
|
||||||
switch (audio_control_cmd_t.cs) {
|
switch (audio_control_cmd_t.cs) {
|
||||||
case 1: { // mute
|
case 1: { // mute
|
||||||
audio_state.mute = buffer->data[0];
|
audio_state.mute = buffer->data[0] ? 0x3 : 0x0;
|
||||||
uint8_t buf[2];
|
|
||||||
buf[0] = 68; // register addr
|
|
||||||
buf[1] = buffer->data[0] ? 0x3 : 0x0; // data
|
|
||||||
i2c_write_blocking(i2c0, PCM_I2C_ADDR, buf, 2, false);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: { // volume
|
case 2: { // volume
|
||||||
|
@ -741,7 +745,11 @@ static const struct usb_transfer_type _audio_cmd_transfer_type = {
|
||||||
|
|
||||||
static bool as_set_alternate(struct usb_interface *interface, uint alt) {
|
static bool as_set_alternate(struct usb_interface *interface, uint alt) {
|
||||||
assert(interface == &as_op_interface);
|
assert(interface == &as_op_interface);
|
||||||
return alt < 2;
|
switch (alt) {
|
||||||
|
case 0: power_down_dac(); return true;
|
||||||
|
case 1: power_up_dac(); return true;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool do_set_current(struct usb_setup_packet *setup) {
|
static bool do_set_current(struct usb_setup_packet *setup) {
|
||||||
|
|
|
@ -56,7 +56,26 @@ typedef struct _audio_state_config {
|
||||||
int16_t target_volume[2];
|
int16_t target_volume[2];
|
||||||
int32_t _target_volume;
|
int32_t _target_volume;
|
||||||
};
|
};
|
||||||
bool mute;
|
union {
|
||||||
|
struct {
|
||||||
|
// Register 68
|
||||||
|
uint8_t mute: 2;
|
||||||
|
uint8_t phase: 1;
|
||||||
|
uint8_t reserved1: 3;
|
||||||
|
uint8_t oversampling: 1;
|
||||||
|
uint8_t reserved2: 1;
|
||||||
|
// Register 69
|
||||||
|
uint8_t zero_fn: 1;
|
||||||
|
uint8_t zero_polarity: 1;
|
||||||
|
uint8_t reserved3: 2;
|
||||||
|
uint8_t de_emphasis: 1;
|
||||||
|
uint8_t de_emphasis_frequency: 2;
|
||||||
|
uint8_t rolloff: 1;
|
||||||
|
};
|
||||||
|
int8_t target_pcm3060_registers[2];
|
||||||
|
int16_t _target_pcm3060_registers;
|
||||||
|
};
|
||||||
|
int16_t pcm3060_registers;
|
||||||
} audio_state_config;
|
} audio_state_config;
|
||||||
extern audio_state_config audio_state;
|
extern audio_state_config audio_state;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue