ガレスタさんのDIY日記

電子回路、Web、組み込み、自作エフェクターを語るblog

MCUXpresso SDK:コーディック周りのHALについて

オーディオフレームを書くにあたっていろいろ調べていたのでそれのメモがてら書いています。


IMXRT1020のコーディック周りは

  • fsl_codec_common.h
  • fsl_codec_common.c
  • fsl_wm8960.c
  • fsl_wm8960.h

の4つからできています。

WM8960_WriteRegの中でCODEC_I2C_WriteReg使っています。
これはCODEC_I2C_WriteRegを自身のI2CAPIで置き換えることで移植性をあげる目的かと思います。

status_t CODEC_I2C_WriteReg(uint8_t i2cAddr,
                            codec_reg_addr_t addrType,
                            uint32_t reg,
                            codec_reg_width_t regWidth,
                            uint32_t value,
                            codec_i2c_send_func_t i2cSendFunc)
{
    uint8_t data[4];
    uint8_t i;

    i = regWidth;
    while (i--)
    {
        data[i] = (uint8_t)value;
        value >>= 8;
    }

    return i2cSendFunc(i2cAddr, reg, addrType, data, regWidth);
}
status_t WM8960_WriteReg(codec_handle_t *handle, uint8_t reg, uint16_t val)
{
    uint8_t cmd, buff;
    uint8_t retval = 0;

    /* The register address */
    cmd = (reg << 1) | ((val >> 8U) & 0x0001U);
    /* Data */
    buff = val & 0xFF;

    retval = CODEC_I2C_WriteReg(handle->slaveAddress, kCODEC_RegAddr8Bit, cmd, kCODEC_RegWidth8Bit, buff,
                                handle->I2C_SendFunc);

    if (retval == kStatus_Success)
    {
        reg_cache[reg] = val;
    }

    return retval;
}

codec_i2c_send_func_tは関数ポインタでこのように記載されている。

typedef status_t (*codec_i2c_send_func_t)(uint8_t deviceAddress, uint32_t subAddress, uint8_t subaddressSize, const uint8_t *txBuff, uint8_t txBuffSize);

んでもってAPIをつなぐAPICODEC_Init(&codecHandle, &boardCodecConfig);となっているわけだが

status_t CODEC_Init(codec_handle_t *handle, codec_config_t *config)
{
    /* Set the handle information */
    handle->I2C_SendFunc = config->I2C_SendFunc;
    handle->I2C_ReceiveFunc = config->I2C_ReceiveFunc;
    memcpy(&handle->op, &config->op, sizeof(codec_operation_t));
    return handle->op.Init(handle, config->codecConfig);
}

codec_config_tのセットに関してはborad.cの以下で記載されている

codec_config_t boardCodecConfig = {
    .I2C_SendFunc = BOARD_Codec_I2C_Send,
    .I2C_ReceiveFunc = BOARD_Codec_I2C_Receive,
    .op.Init = WM8960_Init,
    .op.Deinit = WM8960_Deinit,
    .op.SetFormat = WM8960_ConfigDataFormat
};

そこから下に入るとBOARD_Codec_I2C_Sendがこうなっている。

status_t BOARD_Codec_I2C_Send(
    uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, const uint8_t *txBuff, uint8_t txBuffSize)
{
    return BOARD_LPI2C_Send(BOARD_CODEC_I2C_BASEADDR, deviceAddress, subAddress, subAddressSize, (uint8_t *)txBuff,
                            txBuffSize);
}

ここまででやっと上と下がつながる構造になっている。


てなわけでBOARD_Codec_I2C_Sendを書きかえるか新たに同じ引数の形でつなぎ直すかで対応できると思います。

まとめ

  • codecを追加するときはCODEC_I2C_WriteRegを使って送信関数を記述してinitとかをインプリする。
  • I2Cを変えるときはcodec_config_t構造体にて各種関数をつなぐ
  • 最後にCODEC_Initを呼ぶ