From 062ca82e10a7cddc7e3c55da0e1af9a5dec514c1 Mon Sep 17 00:00:00 2001 From: George Norton Date: Mon, 19 Jun 2023 12:58:16 +0100 Subject: [PATCH] Shuffle cores. --- firmware/code/configuration_manager.c | 64 +++++++++---- firmware/code/configuration_manager.h | 6 +- firmware/code/run.c | 124 ++++++++++++++------------ 3 files changed, 119 insertions(+), 75 deletions(-) diff --git a/firmware/code/configuration_manager.c b/firmware/code/configuration_manager.c index bc9a020..2c43d4c 100644 --- a/firmware/code/configuration_manager.c +++ b/firmware/code/configuration_manager.c @@ -170,17 +170,18 @@ void apply_filter_configuration(filter_configuration_tlv *filters) { } if (type_changed) { + // The memory structure stores the last 2 input samples, we can replay them into + // the new filter rather than starting again from scratch. fix16_t left[2] = { bqf_filters_mem_left[0].x_2, bqf_filters_mem_left[0].x_1 }; fix16_t right[2] = { bqf_filters_mem_right[0].x_2, bqf_filters_mem_right[0].x_1 }; - for (int i=0; idata_len); - memcpy(&working_configuration[inactive_working_configuration][write_offset], buffer->data, buffer->data_len); - write_offset += buffer->data_len; - - const uint16_t transfer_length = ((tlv_header*) working_configuration[inactive_working_configuration])->length; - if (transfer_length && write_offset >= transfer_length) { - // Command complete, fill the result buffer - write_offset = 0; - process_cmd((tlv_header*) working_configuration[inactive_working_configuration]); - read_offset = 0; + if (write_offset + buffer->data_len > CFG_BUFFER_SIZE) + { + // Dont actually write, but this will prevent us for attempting to process this command if a zero byte packet arrives later. + write_offset += buffer->data_len; + printf("Error! Overflow receive buffer [write_offset=%d]\n", write_offset); + tlv_header* result = ((tlv_header*) result_buffer); + result->type = NOK; + result->length = 4; } + else + { + memcpy(&working_configuration[inactive_working_configuration][write_offset], buffer->data, buffer->data_len); + write_offset += buffer->data_len; + const uint16_t transfer_length = ((tlv_header*) working_configuration[inactive_working_configuration])->length; + if (transfer_length && write_offset >= transfer_length) { + // Command complete, fill the result buffer + write_offset = 0; + process_cmd((tlv_header*) working_configuration[inactive_working_configuration]); + read_offset = 0; + } + } usb_grow_transfer(ep->current_transfer, 1); usb_packet_done(ep); } @@ -479,6 +491,7 @@ void config_in_packet(struct usb_endpoint *ep) { if (read_offset >= transfer_length) { // Done read_offset = 0; + write_offset = 0; // If the client reads again, return nothing result->type = NOK; @@ -489,13 +502,32 @@ void config_in_packet(struct usb_endpoint *ep) { usb_packet_done(ep); } +void configuration_ep_on_stall_change(struct usb_endpoint *ep) { + printf("Config EP stall change: %d\n", usb_is_endpoint_stalled(ep)); + if (!usb_is_endpoint_stalled(ep)) { + write_offset = 0; + tlv_header* request = ((tlv_header*) working_configuration[inactive_working_configuration]); + request->type = NOK; + request->length = 0; + } +} + +void configuration_ep_on_cancel(struct usb_endpoint *ep) { + printf("Config EP on cancel\n"); + + write_offset = 0; + tlv_header* request = ((tlv_header*) working_configuration[inactive_working_configuration]); + request->type = NOK; + request->length = 0; +} + void apply_core1_config() { if (reload_config) { - uint32_t ints = save_and_disable_interrupts(); + //uint32_t ints = save_and_disable_interrupts(); reload_config = false; const uint8_t active_configuration = inactive_working_configuration ? 0 : 1; apply_configuration((tlv_header*) working_configuration[active_configuration]); - restore_interrupts(ints); + //restore_interrupts(ints); } } #endif \ No newline at end of file diff --git a/firmware/code/configuration_manager.h b/firmware/code/configuration_manager.h index f1d1086..466cb84 100644 --- a/firmware/code/configuration_manager.h +++ b/firmware/code/configuration_manager.h @@ -25,7 +25,7 @@ struct usb_endpoint; #define INIT_FILTER2(T) { \ filter2 *args = (filter2 *)ptr; \ bqf_##T##_config(SAMPLING_FREQ, args->f0, args->Q, &bqf_filters_left[filter_stages]); \ - bqf_##T##_config(SAMPLING_FREQ, args->f0, args->Q, &bqf_filters_right[filter_stages]); \ + memcpy(&bqf_filters_right[filter_stages], &bqf_filters_left[filter_stages], sizeof(bqf_coeff_t)); \ ptr += sizeof(filter2); \ break; \ } @@ -33,13 +33,15 @@ struct usb_endpoint; #define INIT_FILTER3(T) { \ filter3 *args = (filter3 *)ptr; \ bqf_##T##_config(SAMPLING_FREQ, args->f0, args->db_gain, args->Q, &bqf_filters_left[filter_stages]); \ - bqf_##T##_config(SAMPLING_FREQ, args->f0, args->db_gain, args->Q, &bqf_filters_right[filter_stages]); \ + memcpy(&bqf_filters_right[filter_stages], &bqf_filters_left[filter_stages], sizeof(bqf_coeff_t)); \ ptr += sizeof(filter3); \ break; \ } void config_in_packet(struct usb_endpoint *ep); void config_out_packet(struct usb_endpoint *ep); +void configuration_ep_on_stall_change(struct usb_endpoint *ep); +void configuration_ep_on_cancel(struct usb_endpoint *ep); extern void load_config(); extern void apply_core1_config(); diff --git a/firmware/code/run.c b/firmware/code/run.c index 3d06422..eb595f3 100644 --- a/firmware/code/run.c +++ b/firmware/code/run.c @@ -88,54 +88,6 @@ int main(void) { __wfi(); } -// Here's the meat. It's where the data buffer from USB gets transformed from -// PCM data into I2S data that gets shipped out to the PCM3060. It really -// belongs with the other USB-related code due to its utter indecipherability, -// but it's placed here to emphasize its importance. -static void _as_audio_packet(struct usb_endpoint *ep) { - struct usb_buffer *usb_buffer = usb_current_out_packet_buffer(ep); - int16_t *in = (int16_t *) usb_buffer->data; - int32_t *out = (int32_t *) userbuf; - int samples = usb_buffer->data_len / 2; - - - if (preprocessing.reverse_stereo) { - for (int i = 0; i < samples; i+=2) { - out[i] = in[i+1]; - out[i+1] = in[i]; - } - } - else { - for (int i = 0; i < samples; i++) - out[i] = in[i]; - } - - multicore_fifo_push_blocking(CORE0_READY); - multicore_fifo_push_blocking(samples); - - for (int j = 0; j < filter_stages; j++) { - // Left channel filter - for (int i = 0; i < samples; i += 2) { - fix16_t x_f16 = fix16_mul(fix16_from_int((int16_t) out[i]), preprocessing.preamp); - - x_f16 = bqf_transform(x_f16, &bqf_filters_left[j], - &bqf_filters_mem_left[j]); - - out[i] = (int32_t) fix16_to_int(x_f16); - } - } - - // Block until core 1 has finished transforming the data - uint32_t ready = multicore_fifo_pop_blocking(); - multicore_fifo_push_blocking(CORE0_READY); - - i2s_stream_write(&i2s_write_obj, userbuf, samples * 4); - - // keep on truckin' - usb_grow_transfer(ep->current_transfer, 1); - usb_packet_done(ep); -} - static void update_volume() { if (audio_state._volume != audio_state._target_volume) { @@ -162,22 +114,84 @@ static void update_volume() } } +// Here's the meat. It's where the data buffer from USB gets transformed from +// PCM data into I2S data that gets shipped out to the PCM3060. It really +// belongs with the other USB-related code due to its utter indecipherability, +// but it's placed here to emphasize its importance. +static void _as_audio_packet(struct usb_endpoint *ep) { + struct usb_buffer *usb_buffer = usb_current_out_packet_buffer(ep); + int16_t *in = (int16_t *) usb_buffer->data; + int32_t *out = (int32_t *) userbuf; + int samples = usb_buffer->data_len / 2; + + if (preprocessing.reverse_stereo) { + for (int i = 0; i < samples; i+=2) { + out[i] = in[i+1]; + out[i+1] = in[i]; + } + } + else { + for (int i = 0; i < samples; i++) + out[i] = in[i]; + } + + // Make sure core 1 is ready for us. + multicore_fifo_pop_blocking(); + multicore_fifo_push_blocking(CORE0_READY); + multicore_fifo_push_blocking(samples); + + for (int j = 0; j < filter_stages; j++) { + // Left channel filter + for (int i = 0; i < samples; i += 2) { + fix16_t x_f16 = fix16_mul(fix16_from_int((int16_t) out[i]), preprocessing.preamp); + + x_f16 = bqf_transform(x_f16, &bqf_filters_left[j], + &bqf_filters_mem_left[j]); + + out[i] = (int32_t) fix16_to_int(x_f16); + } + } + + // Block until core 1 has finished transforming the data + uint32_t ready = multicore_fifo_pop_blocking(); + multicore_fifo_push_blocking(CORE0_READY); + + // Update the volume if required. We do this from core1 as + // core0 is more heavily loaded, doing this from core0 can + // lead to audio crackling. + update_volume(); + + // Update filters if required + apply_core1_config(); + + // Wait for core 1 to finish + //multicore_fifo_pop_blocking(); + + // keep on truckin' + usb_grow_transfer(ep->current_transfer, 1); + usb_packet_done(ep); +} + void core1_entry() { uint8_t *userbuf = (uint8_t *) multicore_fifo_pop_blocking(); int32_t *out = (int32_t *) userbuf; + // Signal that the thread has started multicore_fifo_push_blocking(CORE1_READY); while (true) { + // Signal to core 0 that we are ready to accept new data + multicore_fifo_push_blocking(CORE1_READY); + // Block until the userbuf is filled with data uint32_t ready = multicore_fifo_pop_blocking(); while (ready != CORE0_READY) ready = multicore_fifo_pop_blocking(); - uint32_t limit = multicore_fifo_pop_blocking(); + const uint32_t samples = multicore_fifo_pop_blocking(); for (int j = 0; j < filter_stages; j++) { - for (int i = 1; i < limit; i += 2) { + for (int i = 1; i < samples; i += 2) { fix16_t x_f16 = fix16_mul(fix16_from_int((int16_t) out[i]), preprocessing.preamp); x_f16 = bqf_transform(x_f16, &bqf_filters_right[j], @@ -193,13 +207,7 @@ void core1_entry() { // Wait for Core 0 to finish running its filtering before we apply config updates multicore_fifo_pop_blocking(); - // Update filters if required - apply_core1_config(); - - // Update the volume if required. We do this from core1 as - // core0 is more heavily loaded, doing this from core0 can - // lead to audio crackling. - update_volume(); + i2s_stream_write(&i2s_write_obj, userbuf, samples * 4); } } @@ -587,6 +595,7 @@ static const struct usb_transfer_type config_in_transfer_type = { static const struct usb_transfer_type config_out_transfer_type = { .on_packet = config_out_packet, + .on_cancel = configuration_ep_on_cancel, .initial_packet_count = 1, }; @@ -923,6 +932,7 @@ void usb_sound_card_init() { config_in_transfer.type = &config_in_transfer_type; usb_set_default_transfer(&ep_configuration_in, &config_in_transfer); config_out_transfer.type = &config_out_transfer_type; + ep_configuration_out.on_stall_change = configuration_ep_on_stall_change; usb_set_default_transfer(&ep_configuration_out, &config_out_transfer); static struct usb_interface *const boot_device_interfaces[] = {