Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to test firmware and topology files #410

Open
JCesarMolina opened this issue Apr 1, 2022 · 0 comments
Open

How to test firmware and topology files #410

JCesarMolina opened this issue Apr 1, 2022 · 0 comments

Comments

@JCesarMolina
Copy link

Hello,
I follow the tutorial , I modify a little the file amp.c taking into count the switch.c and volume.c , The files compiles.

The code amp.c is:

#include <sof/audio/component.h>
#include <sof/lib/alloc.h>


DECLARE_SOF_RT_UUID("amp", amp_uuid, 0x1d501197, 0xda27, 0x4697,
                 0x80, 0xc8, 0x4e, 0x69, 0x4d, 0x36, 0x00, 0xa0);

DECLARE_TR_CTX(amp_tr, SOF_UUID(amp_uuid), LOG_LEVEL_INFO);

struct amp_comp_data {
        int placeholder;
};

static struct comp_dev *amp_new(const struct comp_driver *drv,
                                struct comp_ipc_config *comp,
                                void *spec);
static void amp_free(struct comp_dev *dev);

static int amp_trigger(struct comp_dev *dev, int cmd);

static int amp_prepare(struct comp_dev *dev);

static int amp_reset(struct comp_dev *dev);

static int amp_copy(struct comp_dev *dev);



struct comp_driver comp_amp = {
    .type = SOF_COMP_AMP,
    .uid = SOF_RT_UUID(amp_uuid),
    .tctx = &amp_tr,
    .ops = {
            .create = amp_new,
            .free = amp_free,
            .params = NULL,
            .cmd = NULL,
            .trigger = amp_trigger,
            .prepare = amp_prepare,
            .reset = amp_reset,
            .copy = amp_copy,
    },
};

static SHARED_DATA struct comp_driver_info comp_amp_info = {
    .drv = &comp_amp,
};

static void sys_comp_amp_init(void)
{
    comp_register(platform_shared_get(&comp_amp_info,sizeof(comp_amp_info)));
}

/**
 *\brief Creat amp component
 *
 *\return Pointer to amp base component device.
**/
static struct comp_dev *amp_new(const struct comp_driver *drv,
                                struct comp_ipc_config *comp,
                                void *spec)
{
    struct comp_dev *dev;
    //struct ipc_config_amp *ampli = spec;
    struct amp_comp_data *cd;

    comp_cl_dbg(&comp_amp, "amp_new()");
    
    //struct sof_ipc_comp_process *amp;
    /*
    struct sof_ipc_comp_process *ipc_amp
            = (struct sof_ipc_comp_process *) comp;
    */
    
    //Allocates memory for the component device and initializes common part
    dev = comp_alloc(drv, sizeof(struct comp_dev));

    if(!dev){
        rfree(dev);
        return NULL;
    }
    dev->ipc_config = *comp;

    cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd));

    if(!cd){
        rfree(dev);
        return NULL;
    }

    //amp = COMP_GET_IPC(dev, sof_ipc_comp_process);
    //int ret;
    //ret = memcpy_s(amp,sizeof(*amp),ipc_amp,sizeof(struct sof_ipc_comp_process)));
    //assert(!ret);

    comp_set_drvdata(dev, cd);
    dev->state = COMP_STATE_READY;

    comp_dbg(dev, "amplifier created");
    
    return dev;
}

// Destructor
static void amp_free(struct comp_dev *dev)
{
    struct comp_data *cd = comp_get_drvdata(dev);
    rfree(cd);
    rfree(dev);
}

//State Transition handler
static int amp_trigger(struct comp_dev *dev, int cmd)
{
    comp_dbg(dev, "amplifier got trigger cm %d, cmd");
    return comp_set_state(dev, cmd);    
}

// Stream Parameters Handler
static int amp_prepare(struct comp_dev *dev)
{
    int ret;
    struct comp_buffer *sink_buf;
    //struct sof_ipc_comp_config *config = dev_comp_config(dev);

    uint32_t sink_per_bytes;

    ret = comp_set_state(dev, COMP_TRIGGER_PREPARE);
    if(ret<0)
        return ret;
    
    if(ret==COMP_STATUS_STATE_ALREADY_SET)
        return PPL_STATUS_PATH_STOP;

    sink_buf = list_first_item(&dev->bsink_list, struct comp_buffer, source_list);

    sink_per_bytes = audio_stream_period_bytes(&sink_buf->stream, dev->frames);

    if(sink_buf->stream.size < dev->ipc_config.periods_sink * sink_per_bytes)
    {
        comp_err(dev, "amp_prepare(): sink_buffer size is insuficient");
        return -ENOMEM;
    }

    comp_dbg(dev, "amplifier prepared");
    return 0;
}

// Reset Handler
static int amp_reset(struct comp_dev *dev)
{
    return comp_set_state(dev, COMP_TRIGGER_RESET);
}

// Signal processing function

static int amp_copy(struct comp_dev *dev)
{
    struct comp_copy_limits cl;
    struct comp_buffer *source;
    struct comp_buffer *sink;
    int frame;
    int channel;
    uint32_t buff_frag = 0;
    uint16_t *src;
    uint16_t *dst;

    source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list);
    sink = list_first_item(&dev->bsink_list,struct comp_buffer,source_list);

    comp_get_copy_limits_with_lock(source, sink, &cl);
    //buffer_invalidate(source, cl.source_bytes);

    for (frame = 0; frame < cl.frames; frame++){
        for (channel = 0; channel < sink->stream.channels; channel++){
            src = audio_stream_read_frag_s16(&source->stream, buff_frag);
            dst = audio_stream_write_frag_s16(&sink->stream, buff_frag);

            *dst = *src;
            ++buff_frag;
        }
    }
    //buffer_writeback(sink, cl.sink_bytes);

    comp_update_buffer_produce(sink, cl.sink_bytes);
    //comp_update_buffer_comsume(source, cl.source_bytes);

    return 0;

}

DECLARE_MODULE(sys_comp_amp_init);

I used the next topology file from here :

#
# Topology for i.MX8MP board with wm8904 codec
#

# Include topology builder
include(`utils.m4')
include(`dai.m4')
include(`pipeline.m4')
include(`sai.m4')
include(`pcm.m4')
include(`buffer.m4')

# Include TLV library
include(`common/tlv.m4')

# Include Token library
include(`sof/tokens.m4')

# Include DSP configuration
include(`platform/imx/imx8.m4')

#
# Define the pipelines
#
# PCM0 <----> volume <-----> SAI3 (wm8904)
#

dnl PIPELINE_PCM_ADD(pipeline,
dnl     pipe id, pcm, max channels, format,
dnl     period, priority, core,
dnl     pcm_min_rate, pcm_max_rate, pipeline_rate,
dnl     time_domain, sched_comp)

# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
# Set 1000us deadline with priority 0 on core 0
PIPELINE_PCM_ADD(sof/pipe-`PPROC'-playback-4test.m4,
	1, 0, 2, s32le,
	1000, 0, 0,
	44100, 44100, 44100)

# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
# Set 1000us deadline with priority 0 on core 0
PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
	2, 0, 2, s32le,
	1000, 0, 0,
	44100, 44100, 44100)
#
# DAIs configuration
#

dnl DAI_ADD(pipeline,
dnl     pipe id, dai type, dai_index, dai_be,
dnl     buffer, periods, format,
dnl     period, priority, core, time_domain)

# playback DAI is SAI3 using 2 periods
# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
DAI_ADD(sof/pipe-dai-playback.m4,
	1, SAI, 3, sai3-wm8904-hifi,
	PIPELINE_SOURCE_1, 2, s32le,
	1000, 0, 0, SCHEDULE_TIME_DOMAIN_DMA)

# capture DAI is SAI3 using 2 periods
# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
DAI_ADD(sof/pipe-dai-capture.m4,
	2, SAI, 3, sai3-wm8904-hifi,
	PIPELINE_SINK_2, 2, s32le,
	1000, 0, 0)

# PCM Low Latency, id 0

dnl PCM_DUPLEX_ADD(name, pcm_id, playback, capture)
PCM_DUPLEX_ADD(Port0, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)

dnl DAI_CONFIG(type, idx, link_id, name, sai_config)
DAI_CONFIG(SAI, 3, 0, sai3-wm8904-hifi,
	SAI_CONFIG(I2S, SAI_CLOCK(mclk, 11565177, codec_mclk_in),
		SAI_CLOCK(bclk, 1411200, codec_provider),
		SAI_CLOCK(fsync, 44100, codec_provider),
        SAI_TDM(2, 32, 3, 3),
		SAI_CONFIG_DATA(SAI, 3, 0)))

and this pipe-volume-playback-4test.m :

# Low Latency Passthrough with volume Pipeline and PCM
#
# Pipeline Endpoints for connection are :-
#
#  host PCM_P --> B0 --> Volume 0 --> B1 --> sink DAI0

# Include topology builder
include(`utils.m4')
include(`buffer.m4')
include(`pcm.m4')
include(`pga.m4')
include(`dai.m4')
include(`mixercontrol.m4')
include(`bytecontrol.m4') # ADDED
include(`pipeline.m4')
include(`amp.m4') # ADDED


#
# Controls
#
# Volume Mixer control with max value of 32
C_CONTROLMIXER(Master Playback Volume, PIPELINE_ID,
	CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
	CONTROLMIXER_MAX(, 32),
	false,
	CONTROLMIXER_TLV(TLV 32 steps from -64dB to 0dB for 2dB, vtlv_m64s2),
	Channel register and shift for Front Left/Right,
	VOLUME_CHANNEL_MAP)

#
# Volume configuration
#

define(DEF_PGA_TOKENS, concat(`pga_tokens_', PIPELINE_ID))
define(DEF_PGA_CONF, concat(`pga_conf_', PIPELINE_ID))

W_VENDORTUPLES(DEF_PGA_TOKENS, sof_volume_tokens,
LIST(`		', `SOF_TKN_VOLUME_RAMP_STEP_TYPE	"2"'
     `		', `SOF_TKN_VOLUME_RAMP_STEP_MS		"20"'))

W_DATA(DEF_PGA_CONF, DEF_PGA_TOKENS)


############### ADDED ###############
# Amp Parameters
include(`amp_bytes.m4')

# Amp Bytes control with max value of 140
# The max size needs to also take into account the space required to hold the control data IPC message
# struct sof_ipc_ctrl_data requires 92 bytes
# AMP priv in amp_bytes.m4 (ABI header (32 bytes) + 2 dwords) requires 40 bytes
# Therefore at least 132 bytes are required for this kcontrol
# Any value lower than that would end up in a topology load error

C_CONTROLBYTES(AMP, PIPELINE_ID,
     CONTROLBYTES_OPS(bytes, 258 binds the control to bytes get/put handlers, 258, 258),
     CONTROLBYTES_EXTOPS(258 binds the control to bytes get/put handlers, 258, 258),
     , , ,
     CONTROLBYTES_MAX(, 140),
     ,
     AMP_priv)

#####################################

#
# Components and Buffers
#

# Host "Passthrough Playback" PCM
# with 2 sink and 0 source periods
W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, 2, 0, SCHEDULE_CORE)

# "Volume" has 2 source and x sink periods
W_PGA(0, PIPELINE_FORMAT, DAI_PERIODS, 2, DEF_PGA_CONF, SCHEDULE_CORE,
	LIST(`		', "PIPELINE_ID Master Playback Volume"))

############### ADDED ###############
# "Amp" has 2 sink periods and 2 source periods
W_AMP(0, PIPELINE_FORMAT, 2, 2, SCHEDULE_CORE,
     LIST(`           ', "AMP"))
#####################################

# Playback Buffers
W_BUFFER(0, COMP_BUFFER_SIZE(2,
	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
	PLATFORM_HOST_MEM_CAP, SCHEDULE_CORE)
W_BUFFER(1, COMP_BUFFER_SIZE(DAI_PERIODS,
	COMP_SAMPLE_SIZE(DAI_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
	PLATFORM_DAI_MEM_CAP, SCHEDULE_CORE)

############### ADDED ###############
# W_BUFFER(name, size, capabilities)

W_BUFFER(2, COMP_BUFFER_SIZE(2,
     COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
     PLATFORM_HOST_MEM_CAP)

#####################################

#
# Pipeline Graph
#
#  host PCM_P --> B2 --> Amp -> B0 --> Volume 0 --> B1 --> sink DAI0

P_GRAPH(pipe-volume-playback-4test, PIPELINE_ID,
	LIST(`		',
	`dapm(N_BUFFER(2), N_PCMP(PCM_ID))',
     `dapm(N_AMP(0), N_BUFFER(2))',
	`dapm(N_BUFFER(0), N_AMP(0))',
	`dapm(N_PGA(0), N_BUFFER(0))',
	`dapm(N_BUFFER(1), N_PGA(0))'))

#
# Pipeline Source and Sinks
#
indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(1))
indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_ID)

ifdef(`CHANNELS_MIN',`define(`LOCAL_CHANNELS_MIN', `CHANNELS_MIN')',
`define(`LOCAL_CHANNELS_MIN', `2')')

#
# PCM Configuration

#
PCM_CAPABILITIES(Passthrough Playback PCM_ID, CAPABILITY_FORMAT_NAME(PIPELINE_FORMAT), PCM_MIN_RATE, PCM_MAX_RATE, LOCAL_CHANNELS_MIN, PIPELINE_CHANNELS, 2, 16, 192, 16384, 65536, 65536)

undefine(`LOCAL_CHANNELS_MIN')
undefine(`DEF_PGA_TOKENS')
undefine(`DEF_PGA_CONF')

Could you explain me if this function COMP_GET_IPC(dev, sof_ipc_comp_process) is still needed? , Sorry if my questions are too basic.
How could i test this firmware from the tutorial ?

Thanks in advanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant