Git Product home page Git Product logo

pico-playground's People

Contributors

drougge avatar jeffawang avatar kilograham avatar lurch avatar peternlewis avatar puresilk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pico-playground's Issues

flash_stream

What needs to be written to the device to make this work?
I've tried img/pack.sh but uf2conf is missing, cant see any references to what this or where it comes from ?

Issue with usb sound card at higher sample rates

Hi, I've tried to implement 96KHz support but I get weird pitch and distorted audio apparently because there's some sample rate mismatch inside the audio system that creates this issue and I would like to know how to make it work with higher frequencies than 48k/16 bits.

Here's the code I changed:

/*
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>

#include "pico/stdlib.h"
#include "pico/usb_device.h"
#include "pico/audio.h"
#include "pico/audio_i2s.h"
#include "pico/multicore.h"
#include "lufa/AudioClassCommon.h"

// todo forget why this is using core 1 for sound: presumably not necessary
// todo noop when muted

CU_REGISTER_DEBUG_PINS(audio_timing)

// ---- select at most one ---
//CU_SELECT_DEBUG_PINS(audio_timing)

// todo make descriptor strings should probably belong to the configs
static char *descriptor_strings[] =
        {
                "PiAudio",
                "Test",
                "13124324"
        };

// todo fix these
#define VENDOR_ID   0x520au
#define PRODUCT_ID  0xf2ddu

#define AUDIO_OUT_ENDPOINT  0x01U
#define AUDIO_IN_ENDPOINT   0x82U

#undef AUDIO_SAMPLE_FREQ
#define AUDIO_SAMPLE_FREQ(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16))

#define AUDIO_MAX_PACKET_SIZE(freq) (uint8_t)(((freq + 999) / 1000) * 4)
#define FEATURE_MUTE_CONTROL 1u
#define FEATURE_VOLUME_CONTROL 2u

#define ENDPOINT_FREQ_CONTROL 1u

struct audio_device_config {
    struct usb_configuration_descriptor descriptor;
    struct usb_interface_descriptor ac_interface;
    struct __packed {
        USB_Audio_StdDescriptor_Interface_AC_t core;
        USB_Audio_StdDescriptor_InputTerminal_t input_terminal;
        USB_Audio_StdDescriptor_FeatureUnit_t feature_unit;
        USB_Audio_StdDescriptor_OutputTerminal_t output_terminal;
    } ac_audio;
    struct usb_interface_descriptor as_zero_interface;
    struct usb_interface_descriptor as_op_interface;
    struct __packed {
        USB_Audio_StdDescriptor_Interface_AS_t streaming;
        struct __packed {
            USB_Audio_StdDescriptor_Format_t core;
            USB_Audio_SampleFreq_t freqs[3];
        } format;
    } as_audio;
    struct __packed {
        struct usb_endpoint_descriptor_long core;
        USB_Audio_StdDescriptor_StreamEndpoint_Spc_t audio;
    } ep1;
    struct usb_endpoint_descriptor_long ep2;
};

static const struct audio_device_config audio_device_config = {
        .descriptor = {
                .bLength             = sizeof(audio_device_config.descriptor),
                .bDescriptorType     = DTYPE_Configuration,
                .wTotalLength        = sizeof(audio_device_config),
                .bNumInterfaces      = 2,
                .bConfigurationValue = 0x01,
                .iConfiguration      = 0x00,
                .bmAttributes        = 0x80,
                .bMaxPower           = 0x32,
        },
        .ac_interface = {
                .bLength            = sizeof(audio_device_config.ac_interface),
                .bDescriptorType    = DTYPE_Interface,
                .bInterfaceNumber   = 0x00,
                .bAlternateSetting  = 0x00,
                .bNumEndpoints      = 0x00,
                .bInterfaceClass    = AUDIO_CSCP_AudioClass,
                .bInterfaceSubClass = AUDIO_CSCP_ControlSubclass,
                .bInterfaceProtocol = AUDIO_CSCP_ControlProtocol,
                .iInterface         = 0x00,
        },
        .ac_audio = {
                .core = {
                        .bLength = sizeof(audio_device_config.ac_audio.core),
                        .bDescriptorType = AUDIO_DTYPE_CSInterface,
                        .bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_Header,
                        .bcdADC = VERSION_BCD(1, 0, 0),
                        .wTotalLength = sizeof(audio_device_config.ac_audio),
                        .bInCollection = 1,
                        .bInterfaceNumbers = 1,
                },
                .input_terminal = {
                        .bLength = sizeof(audio_device_config.ac_audio.input_terminal),
                        .bDescriptorType = AUDIO_DTYPE_CSInterface,
                        .bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal,
                        .bTerminalID = 1,
                        .wTerminalType = AUDIO_TERMINAL_STREAMING,
                        .bAssocTerminal = 0,
                        .bNrChannels = 2,
                        .wChannelConfig = AUDIO_CHANNEL_LEFT_FRONT | AUDIO_CHANNEL_RIGHT_FRONT,
                        .iChannelNames = 0,
                        .iTerminal = 0,
                },
                .feature_unit = {
                        .bLength = sizeof(audio_device_config.ac_audio.feature_unit),
                        .bDescriptorType = AUDIO_DTYPE_CSInterface,
                        .bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_Feature,
                        .bUnitID = 2,
                        .bSourceID = 1,
                        .bControlSize = 1,
                        .bmaControls = {AUDIO_FEATURE_MUTE | AUDIO_FEATURE_VOLUME, 0, 0},
                        .iFeature = 0,
                },
                .output_terminal = {
                        .bLength = sizeof(audio_device_config.ac_audio.output_terminal),
                        .bDescriptorType = AUDIO_DTYPE_CSInterface,
                        .bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal,
                        .bTerminalID = 3,
                        .wTerminalType = AUDIO_TERMINAL_OUT_SPEAKER,
                        .bAssocTerminal = 0,
                        .bSourceID = 2,
                        .iTerminal = 0,
                },
        },
        .as_zero_interface = {
                .bLength            = sizeof(audio_device_config.as_zero_interface),
                .bDescriptorType    = DTYPE_Interface,
                .bInterfaceNumber   = 0x01,
                .bAlternateSetting  = 0x00,
                .bNumEndpoints      = 0x00,
                .bInterfaceClass    = AUDIO_CSCP_AudioClass,
                .bInterfaceSubClass = AUDIO_CSCP_AudioStreamingSubclass,
                .bInterfaceProtocol = AUDIO_CSCP_ControlProtocol,
                .iInterface         = 0x00,
        },
        .as_op_interface = {
                .bLength            = sizeof(audio_device_config.as_op_interface),
                .bDescriptorType    = DTYPE_Interface,
                .bInterfaceNumber   = 0x01,
                .bAlternateSetting  = 0x01,
                .bNumEndpoints      = 0x02,
                .bInterfaceClass    = AUDIO_CSCP_AudioClass,
                .bInterfaceSubClass = AUDIO_CSCP_AudioStreamingSubclass,
                .bInterfaceProtocol = AUDIO_CSCP_ControlProtocol,
                .iInterface         = 0x00,
        },
        .as_audio = {
                .streaming = {
                        .bLength = sizeof(audio_device_config.as_audio.streaming),
                        .bDescriptorType = AUDIO_DTYPE_CSInterface,
                        .bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_General,
                        .bTerminalLink = 1,
                        .bDelay = 1,
                        .wFormatTag = 1, // PCM
                },
                .format = {
                        .core = {
                                .bLength = sizeof(audio_device_config.as_audio.format),
                                .bDescriptorType = AUDIO_DTYPE_CSInterface,
                                .bDescriptorSubtype = AUDIO_DSUBTYPE_CSInterface_FormatType,
                                .bFormatType = 1,
                                .bNrChannels = 2,
                                .bSubFrameSize = 2,
                                .bBitResolution = 16,
                                .bSampleFrequencyType = count_of(audio_device_config.as_audio.format.freqs),
                        },
                        .freqs = {
                                AUDIO_SAMPLE_FREQ(44100),
                                AUDIO_SAMPLE_FREQ(48000),
                                AUDIO_SAMPLE_FREQ(96000)
                        },
                },
        },
        .ep1 = {
                .core = {
                        .bLength          = sizeof(audio_device_config.ep1.core),
                        .bDescriptorType  = DTYPE_Endpoint,
                        .bEndpointAddress = AUDIO_OUT_ENDPOINT,
                        .bmAttributes     = 5,
                        .wMaxPacketSize   = AUDIO_MAX_PACKET_SIZE(AUDIO_FREQ_MAX),
                        .bInterval        = 1,
                        .bRefresh         = 0,
                        .bSyncAddr        = AUDIO_IN_ENDPOINT,
                },
                .audio = {
                        .bLength = sizeof(audio_device_config.ep1.audio),
                        .bDescriptorType = AUDIO_DTYPE_CSEndpoint,
                        .bDescriptorSubtype = AUDIO_DSUBTYPE_CSEndpoint_General,
                        .bmAttributes = 1,
                        .bLockDelayUnits = 0,
                        .wLockDelay = 0,
                }
        },
        .ep2 = {
                .bLength          = sizeof(audio_device_config.ep2),
                .bDescriptorType  = 0x05,
                .bEndpointAddress = AUDIO_IN_ENDPOINT,
                .bmAttributes     = 0x11,
                .wMaxPacketSize   = 3,
                .bInterval        = 0x01,
                .bRefresh         = 2,
                .bSyncAddr        = 0,
        },
};

static struct usb_interface ac_interface;
static struct usb_interface as_op_interface;
static struct usb_endpoint ep_op_out, ep_op_sync;

static const struct usb_device_descriptor boot_device_descriptor = {
        .bLength            = 18,
        .bDescriptorType    = 0x01,
        .bcdUSB             = 0x0110,
        .bDeviceClass       = 0x00,
        .bDeviceSubClass    = 0x00,
        .bDeviceProtocol    = 0x00,
        .bMaxPacketSize0    = 0x40,
        .idVendor           = VENDOR_ID,
        .idProduct          = PRODUCT_ID,
        .bcdDevice          = 0x0200,
        .iManufacturer      = 0x01,
        .iProduct           = 0x02,
        .iSerialNumber      = 0x03,
        .bNumConfigurations = 0x01,
};

const char *_get_descriptor_string(uint index) {
    if (index <= count_of(descriptor_strings)) {
        return descriptor_strings[index - 1];
    } else {
        return "";
    }
}

static struct {
    uint32_t freq;
    int16_t volume;
    int16_t vol_mul;
    bool mute;
} audio_state = {
        .freq = 96000,
};

static struct audio_buffer_pool *producer_pool;

static void _as_audio_packet(struct usb_endpoint *ep) {
    assert(ep->current_transfer);
    struct usb_buffer *usb_buffer = usb_current_out_packet_buffer(ep);
    DEBUG_PINS_SET(audio_timing, 1);
    // todo deal with blocking correctly
    struct audio_buffer *audio_buffer = take_audio_buffer(producer_pool, true);
    DEBUG_PINS_CLR(audio_timing, 1);
    assert(!(usb_buffer->data_len & 3u));
    audio_buffer->sample_count = usb_buffer->data_len / 4;
    assert(audio_buffer->sample_count);
    assert(audio_buffer->max_sample_count >= audio_buffer->sample_count);
    uint16_t vol_mul = audio_state.vol_mul;
    uint16_t *out = (uint16_t *) audio_buffer->buffer->bytes;
    uint16_t *in = (uint16_t *) usb_buffer->data;
    for (unsigned int i = 0; i < audio_buffer->sample_count * 2; i++) {
        out[i] = (uint16_t) ((in[i] * vol_mul) >> 15u);
    }

    give_audio_buffer(producer_pool, audio_buffer);
    // keep on truckin'
    usb_grow_transfer(ep->current_transfer, 1);
    usb_packet_done(ep);
}

static void _as_sync_packet(struct usb_endpoint *ep) {
    assert(ep->current_transfer);
    DEBUG_PINS_SET(audio_timing, 2);
    DEBUG_PINS_CLR(audio_timing, 2);
    struct usb_buffer *buffer = usb_current_in_packet_buffer(ep);
    assert(buffer->data_max >= 3);
    buffer->data_len = 3;

    // todo lie thru our teeth for now
    uint feedback = (audio_state.freq << 14u) / 1000u;

    buffer->data[0] = feedback;
    buffer->data[1] = feedback >> 8u;
    buffer->data[2] = feedback >> 16u;

    // keep on truckin'
    usb_grow_transfer(ep->current_transfer, 1);
    usb_packet_done(ep);
}

static const struct usb_transfer_type as_transfer_type = {
        .on_packet = _as_audio_packet,
        .initial_packet_count = 1,
};

static const struct usb_transfer_type as_sync_transfer_type = {
        .on_packet = _as_sync_packet,
        .initial_packet_count = 1,
};

static struct usb_transfer as_transfer;
static struct usb_transfer as_sync_transfer;

static bool do_get_current(struct usb_setup_packet *setup) {
    usb_debug("AUDIO_REQ_GET_CUR\n");

    if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
        switch (setup->wValue >> 8u) {
            case FEATURE_MUTE_CONTROL: {
                usb_start_tiny_control_in_transfer(audio_state.mute, 1);
                return true;
            }
            case FEATURE_VOLUME_CONTROL: {
                /* Current volume. See UAC Spec 1.0 p.77 */
                usb_start_tiny_control_in_transfer(audio_state.volume, 2);
                return true;
            }
        }
    } else if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_ENDPOINT) {
        if ((setup->wValue >> 8u) == ENDPOINT_FREQ_CONTROL) {
            /* Current frequency */
            usb_start_tiny_control_in_transfer(audio_state.freq, 3);
            return true;
        }
    }
    return false;
}

// todo this seemed like aood guess, but is not correct
uint16_t db_to_vol[91] = {
        0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002,
        0x0002, 0x0002, 0x0003, 0x0003, 0x0004, 0x0004, 0x0005, 0x0005,
        0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000d, 0x000e,
        0x0010, 0x0012, 0x0014, 0x0017, 0x001a, 0x001d, 0x0020, 0x0024,
        0x0029, 0x002e, 0x0033, 0x003a, 0x0041, 0x0049, 0x0052, 0x005c,
        0x0067, 0x0074, 0x0082, 0x0092, 0x00a4, 0x00b8, 0x00ce, 0x00e7,
        0x0104, 0x0124, 0x0147, 0x016f, 0x019c, 0x01ce, 0x0207, 0x0246,
        0x028d, 0x02dd, 0x0337, 0x039b, 0x040c, 0x048a, 0x0518, 0x05b7,
        0x066a, 0x0732, 0x0813, 0x090f, 0x0a2a, 0x0b68, 0x0ccc, 0x0e5c,
        0x101d, 0x1214, 0x1449, 0x16c3, 0x198a, 0x1ca7, 0x2026, 0x2413,
        0x287a, 0x2d6a, 0x32f5, 0x392c, 0x4026, 0x47fa, 0x50c3, 0x5a9d,
        0x65ac, 0x7214, 0x7fff
};

// actually windows doesn't seem to like this in the middle, so set top range to 0db
#define CENTER_VOLUME_INDEX 91

#define ENCODE_DB(x) ((uint16_t)(int16_t)((x)*256))

#define MIN_VOLUME           ENCODE_DB(-CENTER_VOLUME_INDEX)
#define DEFAULT_VOLUME       ENCODE_DB(0)
#define MAX_VOLUME           ENCODE_DB(count_of(db_to_vol)-CENTER_VOLUME_INDEX)
#define VOLUME_RESOLUTION    ENCODE_DB(1)

static bool do_get_minimum(struct usb_setup_packet *setup) {
    usb_debug("AUDIO_REQ_GET_MIN\n");
    if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
        switch (setup->wValue >> 8u) {
            case FEATURE_VOLUME_CONTROL: {
                usb_start_tiny_control_in_transfer(MIN_VOLUME, 2);
                return true;
            }
        }
    }
    return false;
}

static bool do_get_maximum(struct usb_setup_packet *setup) {
    usb_debug("AUDIO_REQ_GET_MAX\n");
    if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
        switch (setup->wValue >> 8u) {
            case FEATURE_VOLUME_CONTROL: {
                usb_start_tiny_control_in_transfer(MAX_VOLUME, 2);
                return true;
            }
        }
    }
    return false;
}

static bool do_get_resolution(struct usb_setup_packet *setup) {
    usb_debug("AUDIO_REQ_GET_RES\n");
    if ((setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK) == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
        switch (setup->wValue >> 8u) {
            case FEATURE_VOLUME_CONTROL: {
                usb_start_tiny_control_in_transfer(VOLUME_RESOLUTION, 2);
                return true;
            }
        }
    }
    return false;
}

static struct audio_control_cmd {
    uint8_t cmd;
    uint8_t type;
    uint8_t cs;
    uint8_t cn;
    uint8_t unit;
    uint8_t len;
} audio_control_cmd_t;

static void _audio_reconfigure() {
    switch (audio_state.freq) {
        case 44100:
        case 48000:
        case 96000:
            break;
        default:
            audio_state.freq = 44100;
    }
    // todo hack overwriting const
    ((struct audio_format *) producer_pool->format)->sample_freq = audio_state.freq;
}

static void audio_set_volume(int16_t volume) {
    audio_state.volume = volume;
    // todo interpolate
    volume += CENTER_VOLUME_INDEX * 256;
    if (volume < 0) volume = 0;
    if (volume >= count_of(db_to_vol) * 256) volume = count_of(db_to_vol) * 256 - 1;
    audio_state.vol_mul = db_to_vol[((uint16_t)volume) >> 8u];
//    printf("VOL MUL %04x\n", audio_state.vol_mul);
}

static void audio_cmd_packet(struct usb_endpoint *ep) {
    assert(audio_control_cmd_t.cmd == AUDIO_REQ_SetCurrent);
    struct usb_buffer *buffer = usb_current_out_packet_buffer(ep);
    audio_control_cmd_t.cmd = 0;
    if (buffer->data_len >= audio_control_cmd_t.len) {
        if (audio_control_cmd_t.type == USB_REQ_TYPE_RECIPIENT_INTERFACE) {
            switch (audio_control_cmd_t.cs) {
                case FEATURE_MUTE_CONTROL: {
                    audio_state.mute = buffer->data[0];
                    usb_warn("Set Mute %d\n", buffer->data[0]);
                    break;
                }
                case FEATURE_VOLUME_CONTROL: {
                    audio_set_volume(*(int16_t *) buffer->data);
                    break;
                }
            }

        } else if (audio_control_cmd_t.type == USB_REQ_TYPE_RECIPIENT_ENDPOINT) {
            if (audio_control_cmd_t.cs == ENDPOINT_FREQ_CONTROL) {
                uint32_t new_freq = (*(uint32_t *) buffer->data) & 0x00ffffffu;
                usb_warn("Set freq %d\n", new_freq == 0xffffffu ? -1 : (int) new_freq);

                if (audio_state.freq != new_freq) {
                    audio_state.freq = new_freq;
                    _audio_reconfigure();
                }
            }
        }
    }
    usb_start_empty_control_in_transfer_null_completion();
    // todo is there error handling?
}


static const struct usb_transfer_type _audio_cmd_transfer_type = {
        .on_packet = audio_cmd_packet,
        .initial_packet_count = 1,
};

static bool as_set_alternate(struct usb_interface *interface, uint alt) {
    assert(interface == &as_op_interface);
    usb_warn("SET ALTERNATE %d\n", alt);
    return alt < 2;
}

static bool do_set_current(struct usb_setup_packet *setup) {
#ifndef NDEBUG
    usb_warn("AUDIO_REQ_SET_CUR\n");
#endif

    if (setup->wLength && setup->wLength < 64) {
        audio_control_cmd_t.cmd = AUDIO_REQ_SetCurrent;
        audio_control_cmd_t.type = setup->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK;
        audio_control_cmd_t.len = (uint8_t) setup->wLength;
        audio_control_cmd_t.unit = setup->wIndex >> 8u;
        audio_control_cmd_t.cs = setup->wValue >> 8u;
        audio_control_cmd_t.cn = (uint8_t) setup->wValue;
        usb_start_control_out_transfer(&_audio_cmd_transfer_type);
        return true;
    }
    return false;
}

static bool ac_setup_request_handler(__unused struct usb_interface *interface, struct usb_setup_packet *setup) {
    setup = __builtin_assume_aligned(setup, 4);
    if (USB_REQ_TYPE_TYPE_CLASS == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) {
        switch (setup->bRequest) {
            case AUDIO_REQ_SetCurrent:
                return do_set_current(setup);

            case AUDIO_REQ_GetCurrent:
                return do_get_current(setup);

            case AUDIO_REQ_GetMinimum:
                return do_get_minimum(setup);

            case AUDIO_REQ_GetMaximum:
                return do_get_maximum(setup);

            case AUDIO_REQ_GetResolution:
                return do_get_resolution(setup);

            default:
                break;
        }
    }
    return false;
}

bool _as_setup_request_handler(__unused struct usb_endpoint *ep, struct usb_setup_packet *setup) {
    setup = __builtin_assume_aligned(setup, 4);
    if (USB_REQ_TYPE_TYPE_CLASS == (setup->bmRequestType & USB_REQ_TYPE_TYPE_MASK)) {
        switch (setup->bRequest) {
            case AUDIO_REQ_SetCurrent:
                return do_set_current(setup);

            case AUDIO_REQ_GetCurrent:
                return do_get_current(setup);

            case AUDIO_REQ_GetMinimum:
                return do_get_minimum(setup);

            case AUDIO_REQ_GetMaximum:
                return do_get_maximum(setup);

            case AUDIO_REQ_GetResolution:
                return do_get_resolution(setup);

            default:
                break;
        }
    }
    return false;
}

void usb_sound_card_init() {
    //msd_interface.setup_request_handler = msd_setup_request_handler;
    usb_interface_init(&ac_interface, &audio_device_config.ac_interface, NULL, 0, true);
    ac_interface.setup_request_handler = ac_setup_request_handler;

    static struct usb_endpoint *const op_endpoints[] = {
            &ep_op_out, &ep_op_sync
    };
    usb_interface_init(&as_op_interface, &audio_device_config.as_op_interface, op_endpoints, count_of(op_endpoints),
                       true);
    as_op_interface.set_alternate_handler = as_set_alternate;
    ep_op_out.setup_request_handler = _as_setup_request_handler;
    as_transfer.type = &as_transfer_type;
    usb_set_default_transfer(&ep_op_out, &as_transfer);
    as_sync_transfer.type = &as_sync_transfer_type;
    usb_set_default_transfer(&ep_op_sync, &as_sync_transfer);

    static struct usb_interface *const boot_device_interfaces[] = {
            &ac_interface,
            &as_op_interface,
    };
    __unused struct usb_device *device = usb_device_init(&boot_device_descriptor, &audio_device_config.descriptor,
                                                         boot_device_interfaces, count_of(boot_device_interfaces),
                                                         _get_descriptor_string);
    assert(device);
    audio_set_volume(DEFAULT_VOLUME);
    _audio_reconfigure();
//    device->on_configure = _on_configure;
    usb_device_start();
}

static void core1_worker() {
    audio_i2s_set_enabled(true);
}

int main(void) {

    stdout_uart_init();

    //gpio_debug_pins_init();
    puts("USB SOUND CARD");

#ifndef NDEBUG
    for(uint i=0;i<count_of(audio_device_config.as_audio.format.freqs);i++) {
        uint freq = audio_device_config.as_audio.format.freqs[i].Byte1 |
                (audio_device_config.as_audio.format.freqs[i].Byte2 << 8u) |
                (audio_device_config.as_audio.format.freqs[i].Byte3 << 16u);
        assert(freq <= AUDIO_FREQ_MAX);
    }
#endif
    // initialize for 48k we allow changing later
    struct audio_format audio_format_48k = {
            .format = AUDIO_BUFFER_FORMAT_PCM_U16,
            .sample_freq = 96000,
            .channel_count = 2,
    };

    struct audio_buffer_format producer_format = {
            .format = &audio_format_48k,
            .sample_stride = 4
    };

    producer_pool = audio_new_producer_pool(&producer_format, 8, 96); // todo correct size
    bool __unused ok;
    struct audio_i2s_config config = {
            .data_pin = PICO_AUDIO_I2S_DATA_PIN,
            .clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE,
            .dma_channel = 0,
            .pio_sm = 0,
    };

    const struct audio_format *output_format;
    output_format = audio_i2s_setup(&audio_format_48k, &config);
    if (!output_format) {
        panic("PicoAudio: Unable to open audio device.\n");
    }

    ok = audio_i2s_connect_extra(producer_pool, false, 2, 96, NULL);
    assert(ok);
    usb_sound_card_init();

    multicore_launch_core1(core1_worker);
    printf("HAHA %04x %04x %04x %04x\n", MIN_VOLUME, DEFAULT_VOLUME, MAX_VOLUME, VOLUME_RESOLUTION);
    // MSD is irq driven
    while (1) __wfi();
}

In the CMake I did this change here:

AUDIO_FREQ_MAX=96000

Hope to get a response back as this project seems dead. I was thinking if it would also make more sense to recreate the entire soundcard using TinyUSB at this point...

Screenshots for video?

It would be great to have some screenshots for the video demos. Other demos might benefit as well.

Sprite_Demo

I know the floating head sprites are arrays of char hex but i cant find an image converter that seems to work. When i replace the original sprite hex with something i get from any converters i do find, nothing appears. Not even a few pixels ! Im not a great coder but i wanna display my own sprites atleast. I have been successful with changing everything but the sprite itself like speed, position, bg color

Licence for the Ubuntu Mono font

I think that the font files:

include a rendered copy of the font "Ubuntu Mono". If so, the licence (https://ubuntu.com/legal/font-licence) for that font states:

Each copy of the Font Software must contain the above copyright notice and this licence. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.

I Am Not A Lawyer, and maybe rendering a font down to a bitmap doesn't constitute a "copy" of the font, but giving a link to Ubuntu as the source seems reasonable nonetheless. Some notes on how you rendered the font would also be handy, in case anyone wants a different font size.

Popcorn Convertor and/or Samples

Is there any possibility you could publish the video conversion tool and/or some samples for the Popcorn Media Player app in pico-playground.

This is what README.mb currently says:

This is a movie player for 30fps 320x240 movies with 44100 stereo sound, read in a custom format from SD card... it can even play backwards :-) TODO: add a link to big buck bunny in the right format TODO: add converter

Many thanks

Problem with UART in hello_sleep example

I am currently experimenting with the sleep/dormant modes of the Raspberry Pi Pico. As a base I am using the examples hello_sleep respectively hello_dormant. The problem I encountered: After going to sleep, no printf() statements will be printed to the uart.

The only text I'll ever see using a serial monitor is the following:
[Connected]
Hello Sleep!
Switching to XOSC

I am using a Mac. Thus, I don't know whether Windows 10 and Linux have the same issue.
Is there anything I need to consider when sleeping or recovering from sleep? Saving the clock registers before sleep and restoring them after sleep did not work either.

How to add usb printf to flash-stream dma example?

I want to draw 640x320 display while also monitoring capacitive touch panel every ~5ms via i2c, so I tried to elaborate on flash-stream example, but failed just to print out smth through usb.

I tried adding second core entry to output usb string with 1 second delay, or vice versa - to move vga routine to second core, while outputting string in main one: in first case its just halts, in second while moving vga to second core - it manages to draw pictures normally but usb tty device not even recognized.

After debugging a bit - I found out that everything works just fine right until __no_inline_not_in_flash_func(flash_bulk_read) function is reached, and its first line ssi_hw->ssienr = 0; breaks it. I'm a newbie to pico and not familiar with this code.

So does anyone knows if its possible to use usb cdc for communication in this large pictures dma example and how to do it, or it is because pico uses all its resources to render images and have no compute power for usb stack (and potentially my i2c touch panel routine on top of it too)? Thx.

Not able to build repository - `Unknown CMake command Include build folder as part of .gitignore`

I am getting below error when trying to compile pico-playground repository

$ cmake .. -DBOARD=pico_w
Using PICO_SDK_PATH from environment ('/home/juan/repos/pico-sdk')
PICO_SDK_PATH is /home/juan/repos/pico-sdk
Defaulting PICO_PLATFORM to rp2040 since not specified.
Defaulting PICO platform compiler to pico_arm_gcc since not specified.
-- Defaulting build type to 'Release' since not specified.
PICO compiler is pico_arm_gcc
Defaulting PICO_EXTRAS_PATH as sibling of PICO_SDK_PATH: /home/juan/repos/pico-sdk/../pico-extras
-- The C compiler identification is GNU 10.3.1
-- The CXX compiler identification is GNU 10.3.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done

...
...
...

Build type is Release
Defaulting PICO target board to pico since not specified.
Using board configuration from /home/juan/repos/pico-sdk/src/boards/include/boards/pico.h
-- Found Python3: /usr/bin/python3.10 (found version "3.10.12") found components: Interpreter 
CMake Warning at /home/juan/repos/pico-sdk/src/rp2_common/tinyusb/CMakeLists.txt:10 (message):
  TinyUSB submodule has not been initialized; USB support will be unavailable

  hint: try 'git submodule update --init' from your SDK directory
  (/home/juan/repos/pico-sdk).


CMake Error at tone/christmas_melody/CMakeLists.txt:12 (example_auto_set_url):
  Unknown CMake command "example_auto_set_url".


-- Configuring incomplete, errors occurred!
See also "/home/juan/repos/pico-playground/build/CMakeFiles/CMakeOutput.log".
See also "/home/juan/repos/pico-playground/build/CMakeFiles/CMakeError.log".

$

LVGL for scanline generation

Hi,

Since I've learned that this project does not use a full framebuffer I recalled the LVGL project, that does the same for low ram microcontrollers.

Do you think that the pico would be fast enough to render the lines on demand?

Thank you.

Sprite composition in ram, from flash.

Hello everybody,

I'd like to make a screen with a bunch of sprites that are a combination of simpler images.

The base images would be stored in flash and composed into ram on demand. The display would work from RAM then...

I understand that the packed images might be rle encoded and some work will be needed to compose them if this code is not already there somewhere else in the project.

What do you think?

Thank you.

audio/sine_wave/CMakeLists.txt wrong I2S pins

I think it is impossible to test this I2S audio application with these pins configurations:

https://github.com/raspberrypi/pico-playground/tree/master/audio/sine_wave

audio/sine_wave/CMakeLists.txt

            USE_AUDIO_I2S=1
#            PICO_AUDIO_I2S_DATA_PIN=22   - is acessible 
#            PICO_AUDIO_I2S_CLOCK_PIN_BASE=23 - not acessible 

/audio/sine_wave/sine_wave.c

#if PICO_ON_DEVICE
#include "pico/binary_info.h"
bi_decl(bi_3pins_with_names(PICO_AUDIO_I2S_DATA_PIN, "I2S DIN", PICO_AUDIO_I2S_CLOCK_PIN_BASE, "I2S BCK", PICO_AUDIO_I2S_CLOCK_PIN_BASE+1, "I2S LRCK"));
#endif

OK = PICO_AUDIO_I2S_DATA_PIN, "I2S DIN" = GPIO22
Not acessible = PICO_AUDIO_I2S_CLOCK_PIN_BASE, "I2S BCK" = GPIO23
Not acessible = PICO_AUDIO_I2S_CLOCK_PIN_BASE+1, "I2S LRCK" = GPIO24

Thanks

usb_sound_card.c - line 290 "todo lie thru our teeth for now"

Isochronous data with asynchronous USB transfer type

Line 290 states: todo lie thru our teeth for now in the _as_sync_packet' function. What exactly is meant by this? What does this function do?

Does this mean the asynchronous USB transfer type is not actually providing correct feedback to the USB Host and just spoofing the feedback loop to the host? The function can be seen below. When debugging I noticed that this function is called many times which is what could be expected for something that is used as feedback loop to a USB host device. I just do not comprehend where or when this feedback is returned to the USB host device.

static void _as_sync_packet(struct usb_endpoint *ep) {
    assert(ep->current_transfer);
    DEBUG_PINS_SET(audio_timing, 2);
    DEBUG_PINS_CLR(audio_timing, 2);
    struct usb_buffer *buffer = usb_current_in_packet_buffer(ep);
    assert(buffer->data_max >= 3);
    buffer->data_len = 3;

    // todo lie thru our teeth for now
    uint feedback = (audio_state.freq << 14u) / 1000u;

    buffer->data[0] = feedback;
    buffer->data[1] = feedback >> 8u;
    buffer->data[2] = feedback >> 16u;

    printf("_as_sync_packet function --> data[0]: %d, data[1]: %d, data[2]: %d\n\r");

    // keep on truckin'
    usb_grow_transfer(ep->current_transfer, 1);
    usb_packet_done(ep);
}

convert images for sprite_demo

I've tried multiple combinations with different bgar5515 converters (including the packtiles script) but all of them don't render properly (draws only 1 line, some lines are skipped). I'll provide images if anyone wants them. What is the proper way to convert images?

Pico freezes due to hello_sleep.c and hello_dormant.c

Entering sleep/dormant mode will work a couple of times, but then the Pico gets frozen. There must be configurations which are not recovered after wake-up. Saving and then restoring the clock registers solves only some issues, but does not prevent the system from getting stuck. Reenabling the ROSC does not help either: rosc_write(&rosc_hw->ctrl, ROSC_CTRL_ENABLE_BITS);

Feature request

This looks a lot more interesting than the current demos, but the build system is Windows only.

Some co-operation between these two projects could produce great results. Currently I lack the skill to modify the build systems or change the PIO code, but maybe I can get someone with more skill than me interested in looking at this.

http://www.breatharian.eu/hw/picovga/index_en.html

USB Sound Card ceases function after some time of use

I have a couple of projects I'd like to use the USB Sound Card app for, however I Don't know enough about coding to fix the issue it has.

After aproximately 20 minutes it will stop working, the host usb port will also stop working and will not work again unless you reboot.

Is it possible that this issue could be fixed?

sprite_demo fails on VGA board

Built with PICO_BOARD=vgaboard the sprite_demo fails immediately at runtime with the following message:

*** PANIC ***
System clock (192000000) must be an integer multiple of the requested pixel clock (25000000).

Changing the sys clock value to a multiple of 25MHz succeeds. Seemed to need 250MHz to render the whole screen but the OC is unstable after a minute or so on my Pimoroni VGA demo board:

set_sys_clock_khz(250000, true);

This may well not be the right fix :)

TURBO_BOOST breaks vga color

Hi,

I have noticed that enabling the TURBO_BOOST define breaks the correct colors display on the flash_stream sample vga_mode_640x480_60 .

Without TURBO_BOOST, the number is crisp and the blue gradient is perfect.

With TURBO_BOOST, a blue gradient turns to like 64 color dithered green.

Also, white blobs are leaking red pixels to the right.

Are these artifacts usually caused by vga timing error?

Thank you.

image

USB Sound Card instructions for Linux

Any chance for a bit of extra info on how to use the USB sound card under Linux? On Windows it just pops up as a sound device.

After plugging in, this is what I get:

[242885.880287] usb 1-3: new full-speed USB device number 12 using xhci_hcd
[242885.898555] usb 1-3: New USB device found, idVendor=2e8a, idProduct=fedd, bcdDevice= 2.00
[242885.898563] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[242885.898568] usb 1-3: Product: Pico Examples Sound Card
[242885.898571] usb 1-3: Manufacturer: Raspberry Pi
[242885.898574] usb 1-3: SerialNumber: 0123456789AB

There's no USB interfaces detected, am I missing some kernel driver?

How to use vga_mode_tft_800x480_50 mode?

Hello everybody,

I am experimenting with the flash stream example and a widescreen 800x480 tft.

Currently, with the project set to 640x480, the images are not completely shown as its corners are cut out.

The tft controller OSD shows 640x480 correctly. The PNG has the same format, but it is shown bigger than the screen.

I'd like to try higher resolutions as this txt supports 800x480.

setting VGA_MODE to vga_mode_tft_800x480_50 breaks with:

[ 44%] Linking CXX executable flash_stream.elf
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: CMakeFiles/flash_stream.dir/flash_stream.c.obj: in function `render_loop':
flash_stream.c:(.time_critical.render_loop+0x8c): undefined reference to `vga_mode_tft_800x480_50'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: CMakeFiles/flash_stream.dir/flash_stream.c.obj: in function `vga_main':
flash_stream.c:(.text.vga_main+0x14): undefined reference to `vga_mode_tft_800x480_50'
collect2: error: ld returned 1 exit status
make[2]: *** [scanvideo/flash_stream/CMakeFiles/flash_stream.dir/build.make:747: scanvideo/flash_stream/flash_stream.elf] Error 1
make[1]: *** [CMakeFiles/Makefile2:3058: scanvideo/flash_stream/CMakeFiles/flash_stream.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

It looks like pico_scanvideo_dpi is being used and is not including the proper vga configurations.

What can I do?

Flash stream example producing messed color results

I'm new to pico and failing to understand why I'm getting messed up image rendering with flash_stream example in scanline directory. Steps to reproduce screenshots I get:

  1. run ./pack.sh in img directory - it will produce 3 bin files and cat them into one pack.bin
  2. run sudo picotool load pack.bin -o 1003c000 to upload pack.bin into pico. The original command uses uf2conv -f pico -b 0x1003c000 pack.bin -o pack.uf2 - but I don't know what uf2conv is and where to find it, so as this person on raspberry forum, and I took his suggested command with picotool - uf2conv thread
  3. build flash_stream.uf2 and drag it into pico folder with file manager

Having done those I see such strange result, I know little about image processing and what exactly wrong with those:
IMG_20221201_200548
IMG_20221201_200552

I tried this on two different monitors, one big 24 inch monitor, and one small 7 inch 40 pin ttl monitor through the scaler - the result is equal.

Running demo1 example with floating raspberry on a blue background works without any issue, so I doubt its a wiring problem.

I also tried to change packing command a bit - e.g. changing format and removing d in ./packtiles -sdf bgar5515 Voss_by_fortuneblues.png voss.bin , it changes some things but colors are still messed.

How to properly include tinyusb in the examples

Hi,

I am expanding the flash_stream example with usb functionality can the build is failing with:

/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: CMakeFiles/flash_stream.dir/flash_stream.c.obj: in function `render_loop':
flash_stream.c:(.time_critical.render_loop+0x8a): undefined reference to `tud_task'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: CMakeFiles/flash_stream.dir/flash_stream.c.obj: in function `vga_main':
flash_stream.c:(.text.vga_main+0x3a): undefined reference to `tud_init'
collect2: error: ld returned 1 exit status
make[2]: *** [scanvideo/flash_stream/CMakeFiles/flash_stream.dir/build.make:1129: scanvideo/flash_stream/flash_stream.elf] Error 1
make[1]: *** [CMakeFiles/Makefile2:2439: scanvideo/flash_stream/CMakeFiles/flash_stream.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

Something is not going right with the library include I suspect.

I have modified the example cmakelists.txt to be:

if (PICO_ON_DEVICE AND TARGET pico_scanvideo_dpi)
    include(${PICO_SDK_PATH}/lib/tinyusb/hw/bsp/family_support.cmake)

    family_initialize_project(flash_stream ${CMAKE_CURRENT_LIST_DIR})

    add_executable(flash_stream
            flash_stream.c
            usb_descriptors.c
            )
    target_link_libraries(flash_stream PRIVATE
            pico_multicore
            pico_stdlib
            pico_scanvideo_dpi
            hardware_dma
            tinyusb_board
            tinyusb_device
            )
    target_compile_definitions(flash_stream PRIVATE
            PICO_SCANVIDEO_MAX_SCANLINE_BUFFER_WORDS=500
            )
    target_include_directories(flash_stream PUBLIC
        ${CMAKE_CURRENT_LIST_DIR})
    pico_add_extra_outputs(flash_stream)
    pico_enable_stdio_usb(flash_stream 0)
    pico_enable_stdio_uart(flash_stream 0)
    # Uncomment this line to enable fix for Errata RP2040-E5 (the fix requires use of GPIO 15)
    #target_compile_definitions(flash_stream PUBLIC PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1)
    pico_add_extra_outputs(flash_stream)
    family_configure_device_example(flash_stream)
endif ()

And flash_stream.c includes:

#include "tusb_config.h"
#include "bsp/board.h"
#include "device/usbd.h"
#include "class/hid/hid_device.h"
#include "tusb.h"

It does compile the file containing the missing functions:

[ 80%] Building C object scanvideo/flash_stream/CMakeFiles/flash_stream.dir/home/barbiani/pico-sdk/lib/tinyusb/src/portable/raspberrypi/rp2040/rp2040_usb.c.obj
[ 81%] Building C object scanvideo/flash_stream/CMakeFiles/flash_stream.dir/home/barbiani/pico-sdk/lib/tinyusb/src/device/usbd.c.obj
[ 82%] Building C object scanvideo/flash_stream/CMakeFiles/flash_stream.dir/home/barbiani/pico-sdk/lib/tinyusb/src/device/usbd_control.c.obj

I have followed other tinyusb examples and included what I found to be necessary, but the linking step is still failing.

Any clues?

Thank you.

Unable to run demo's on Pico Demo Board

Hi! I've just got my VGA pico demo board and have tried running the examples on it, however I can't seem to get any VGA output at all, I have tested the pins for Hsync, Vsync and the colours and they seem to be outputting at around 31/16KHz or a multiple of them which seems correct to me.

So I'm wondering if my modern LCD monitor doesn't like these super-low resolution modes? My monitor detects a signal but just stays black.

Strangely, I also can't get audio to play, the USB sound card is the only example I could partially get running with the PWM outputting a very distorted sound in only the left channel.

I can't tell if I'm doing something wrong or my board is faulty.

8080 and 6800 parallel bus example

On Rp2040 Datasheet page 324,
I can read: "The programmable input/output block (PIO) is a versatile hardware interface. It can support a variety of IO standards, including: 8080 and 6800 parallel bus..."

Is there an example about 8080 parallel bus ?
Tnx

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.