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 }, | ||||
|         .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; | ||||
|  |  | |||
|  | @ -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
 | ||||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 George Norton
						George Norton