diff --git a/firmware/code/configuration_manager.c b/firmware/code/configuration_manager.c index 57b6a18..c453990 100644 --- a/firmware/code/configuration_manager.c +++ b/firmware/code/configuration_manager.c @@ -56,12 +56,12 @@ static const default_configuration default_config = { .f4 = { HIGHSHELF, {0}, 8400, 2, 0.7 }, .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. #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); #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 bool reload_config = false; -static bool save_config = false; -static bool factory_reset = false; static uint16_t write_offset = 0; static uint16_t read_offset = 0; @@ -208,13 +206,20 @@ bool validate_configuration(tlv_header *config) { break; case PREPROCESSING_CONFIGURATION: { 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)) { printf("Preprocessing size missmatch: %u != %zu\n", tlv->length, sizeof(preprocessing_configuration_tlv)); return false; } 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: // Unknown TLVs are not invalid, just ignored. break; @@ -253,6 +258,14 @@ bool apply_configuration(tlv_header *config) { preprocessing.reverse_stereo = preprocessing_config->reverse_stereo; 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: break; } @@ -275,15 +288,16 @@ void load_config() { } #ifndef TEST_TARGET -// Must be in RAM -uint8_t flash_buffer[FLASH_PAGE_SIZE]; bool __no_inline_not_in_flash_func(save_configuration)() { const uint8_t active_configuration = inactive_working_configuration ? 0 : 1; tlv_header* config = (tlv_header*) working_configuration[active_configuration]; if (validate_configuration(config)) { + power_down_dac(); + const size_t config_length = config->length - (size_t)((size_t)config->value - (size_t)config); // Write data to flash + uint8_t flash_buffer[FLASH_PAGE_SIZE]; flash_header_tlv* flash_header = (flash_header_tlv*) flash_buffer; flash_header->header.type = FLASH_HEADER; 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; memcpy((void*)(flash_header->tlvs), config->value, config_length); - power_down_dac(); - uint32_t ints = save_and_disable_interrupts(); flash_range_erase(USER_CONFIGURATION_OFFSET, FLASH_SECTOR_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; } +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) { tlv_header* result = ((tlv_header*) result_buffer); switch (cmd->type) { @@ -318,8 +339,7 @@ bool process_cmd(tlv_header* cmd) { } break; case SAVE_CONFIGURATION: { - if (cmd->length == 4) { - save_config = true; + if (cmd->length == 4 && save_configuration()) { result->type = OK; result->length = 4; return true; @@ -327,8 +347,7 @@ bool process_cmd(tlv_header* cmd) { break; } case FACTORY_RESET: { - if (cmd->length == 4) { - factory_reset = true; + if (cmd->length == 4 && factory_reset()) { flash_header_tlv flash_header = { 0 }; result->type = OK; result->length = 4; @@ -411,21 +430,6 @@ void config_in_packet(struct usb_endpoint *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() { if (reload_config) { reload_config = false; diff --git a/firmware/code/configuration_manager.h b/firmware/code/configuration_manager.h index cb5bfde..f1d1086 100644 --- a/firmware/code/configuration_manager.h +++ b/firmware/code/configuration_manager.h @@ -41,7 +41,6 @@ struct usb_endpoint; void config_in_packet(struct usb_endpoint *ep); void config_out_packet(struct usb_endpoint *ep); extern void load_config(); -extern void apply_core0_config(); extern void apply_core1_config(); #endif // CONFIGURATION_MANAGER_H \ No newline at end of file diff --git a/firmware/code/configuration_types.h b/firmware/code/configuration_types.h index e58961a..7e67ce9 100644 --- a/firmware/code/configuration_types.h +++ b/firmware/code/configuration_types.h @@ -96,6 +96,15 @@ typedef struct __attribute__((__packed__)) _filter_configuration_tlv { const uint8_t filters[]; } 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 { tlv_header header; uint16_t current_version; diff --git a/firmware/code/run.c b/firmware/code/run.c index 5cb48b1..1ec2ffe 100644 --- a/firmware/code/run.c +++ b/firmware/code/run.c @@ -51,6 +51,7 @@ static uint8_t *userbuf; audio_state_config audio_state = { .freq = 48000, + .de_emphasis_frequency = 0x1, // 48khz }; preprocessing_config preprocessing = { @@ -97,8 +98,6 @@ static void _as_audio_packet(struct usb_endpoint *ep) { int32_t *out = (int32_t *) userbuf; int samples = usb_buffer->data_len / 2; - // Update filters if required - apply_core0_config(); if (preprocessing.reverse_stereo) { for (int i = 0; i < samples; i+=2) { @@ -152,6 +151,15 @@ static void update_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() { @@ -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) { switch (setup->wValue >> 8u) { 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; } 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) { switch (audio_control_cmd_t.cs) { case 1: { // mute - audio_state.mute = buffer->data[0]; - 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); + audio_state.mute = buffer->data[0] ? 0x3 : 0x0; break; } 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) { 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) { diff --git a/firmware/code/run.h b/firmware/code/run.h index 6fb0a7e..2a64beb 100644 --- a/firmware/code/run.h +++ b/firmware/code/run.h @@ -56,7 +56,26 @@ typedef struct _audio_state_config { int16_t target_volume[2]; 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; extern audio_state_config audio_state;