API GUIDE / PWMA / HAL

PWMA HAL 接口

1. HAL 公开类型

1.1 Level、data type、endian、precision

类型 值
hal_pwma_level_t HAL_PWMA_LEVEL_LOW/HIGH
hal_pwma_data_type_t HAL_PWMA_DATA_UNSIGNED/SIGNED
hal_pwma_endian_t HAL_PWMA_ENDIAN_LITTLE/BIG
hal_pwma_precision_t HAL_PWMA_PRECISION_8BIT/16BIT

1.2 hal_pwma_format_t

值 采样率
HAL_PWMA_FORMAT_8K 8 kHz
HAL_PWMA_FORMAT_16K 16 kHz
HAL_PWMA_FORMAT_32K 32 kHz
HAL_PWMA_FORMAT_44_1K 44.1 kHz
HAL_PWMA_FORMAT_48K 48 kHz

该字段是硬件 sample format 编码,不改变 PWM carrier。

1.3 State

状态 说明
HAL_PWMA_STATE_RESET handle 已绑定,但全局初始化未完成
HAL_PWMA_STATE_READY 初始化完成,输出关闭
HAL_PWMA_STATE_ACTIVE waveform output 已 enable

1.4 Event 和 status

hal_pwma_event_t:

值 说明
HAL_PWMA_EVENT_DMA_FIFO_EMPTY DMA FIFO empty level event
HAL_PWMA_EVENT_FIRST_WAVE 首个 waveform 已产生

hal_pwma_status_t 字段:

字段 说明
is_busy shadow update 尚在处理
is_working AUDIO_WORK=1
is_dma_fifo_empty DMA_FE=1
is_first_wave FST_WAVE=1
is_dma_enabled DMA_EN=1
is_output_enabled CNT_EN=1
is_soft_reset_asserted SOFT_RESET_STATUS=0

1.5 hal_pwma_init_t

typedef struct {
    hal_pwma_data_type_t data_type;
    hal_pwma_endian_t endian;
    hal_pwma_level_t init_level;
    hal_pwma_level_t idle_level;
    hal_pwma_precision_t precision;
    hal_pwma_format_t format;
    uint32_t module_clock_hz;
    uint32_t prescaler;
    uint32_t period_threshold;
    uint32_t high_threshold;
    uint32_t volume_gain;
    bool dma_enable;
    bool volume_down;
    bool first_wave_interrupt_masked;
    bool dma_fifo_empty_interrupt_masked;
} hal_pwma_init_t;

hal_pwma_struct_init() 默认值:

字段 默认值
data type unsigned
endian little
initial/idle level low
precision 8 bit
format 8 kHz
module clock 0,表示不修改 CGU rate
prescaler 0
period threshold 0
high threshold 0
volume gain/down 0/false
DMA disabled
interrupts masked

默认 period_threshold=0 不满足初始化要求。调用方必须显式设置至少为 2 的 AUDIO_TH。

1.6 配置结构

hal_pwma_input_config_t 配置 signedness、endian、precision 和 format。

hal_pwma_timing_config_t 配置 prescaler、AUDIO_TH 和 AUDIO_HIGH。

hal_pwma_output_level_config_t 配置 init/idle level。

hal_pwma_volume_config_t 配置 volume down 和 8-bit gain。

hal_pwma_interrupt_config_t 配置两个 interrupt mask。

hal_pwma_dma_config_t 只配置 PWMA-side DMA request enable。

1.7 hal_pwma_handle_t

handle 包含 instance、state、clock_enabled、实际 module_clock_hz、 user_data、DMA-empty callback 和 first-wave callback。handle 由调用方拥有。

2. HAL 生命周期接口

2.1 hal_pwma_struct_init

void hal_pwma_struct_init(hal_pwma_init_t *pwma_init);

填入默认值,不访问硬件。pwma_init == NULL 时无操作。

2.2 hal_pwma_handle_init

error_code_t hal_pwma_handle_init(hal_pwma_handle_t *handle,
                                  pwma_regs_t *instance);

绑定 PWMA 实例并清零软件状态,不访问硬件。

2.3 hal_pwma_init

error_code_t hal_pwma_init(hal_pwma_handle_t *handle,
                           const hal_pwma_init_t *pwma_init);

执行顺序:

  1. 校验配置。
  2. 设置 CPM CGU_PWMA rate,并打开 PWMA gate。
  3. 读回实际 module clock。
  4. 关闭 waveform output。
  5. 配置 input、timing、levels、volume、interrupt 和 DMA request。
  6. 写 AUDIO_UPDATE。
  7. 进入 READY。

任一寄存器配置失败时关闭 PWMA clock/gate,并回到 RESET。

2.4 hal_pwma_deinit

error_code_t hal_pwma_deinit(hal_pwma_handle_t *handle);

mask interrupts、关闭 DMA 和 output、清 first-wave 和 FIFO,然后释放 PWMA clock gate。 CGU divider 保持最后一次配置。成功回到 RESET。

3. HAL 配置接口

3.1 hal_pwma_configure_input

error_code_t hal_pwma_configure_input(
    hal_pwma_handle_t *handle,
    const hal_pwma_input_config_t *input_config);

写 DATA_TYPE、ENDIAN、PRECISION、FORMAT。建议在 stream 启动前使用。

3.2 hal_pwma_configure_timing

error_code_t hal_pwma_configure_timing(
    hal_pwma_handle_t *handle,
    const hal_pwma_timing_config_t *timing_config);

写 PRESCALE、AUDIO_TH、AUDIO_HIGH。

注意:

  • period_threshold >= 2。
  • high_threshold 必须落在 AUDIO_HIGH 位域内。
  • spec 要求运行中不要改变 PRESCALE;HAL 不替代调用方执行该时序约束。

3.3 hal_pwma_configure_output_level

error_code_t hal_pwma_configure_output_level(
    hal_pwma_handle_t *handle,
    const hal_pwma_output_level_config_t *output_level_config);

配置 starting/idle output level。该设置决定没有 waveform 时的引脚电平。

3.4 hal_pwma_configure_volume

error_code_t hal_pwma_configure_volume(
    hal_pwma_handle_t *handle,
    const hal_pwma_volume_config_t *volume_config);

只写 AUDIO_VOLUME shadow。需要调用 hal_pwma_apply_update() 才生效。运行中动态调节 建议使用该接口并串行化。

3.5 hal_pwma_configure_interrupt

error_code_t hal_pwma_configure_interrupt(
    hal_pwma_handle_t *handle,
    const hal_pwma_interrupt_config_t *interrupt_config);

设置 first-wave 和 DMA-FIFO-empty mask。bit=1 表示 masked。

3.6 hal_pwma_configure_dma

error_code_t hal_pwma_configure_dma(
    hal_pwma_handle_t *handle,
    const hal_pwma_dma_config_t *dma_config);

只控制 AUDIO_CON.DMA_EN,不启动 PDMA。

3.7 hal_pwma_apply_update

error_code_t hal_pwma_apply_update(hal_pwma_handle_t *handle);

写 AUDIO_UPDATE.UPDATE=1。该接口可在 READY/ACTIVE 状态调用。

4. HAL 控制和状态接口

4.1 hal_pwma_start

error_code_t hal_pwma_start(hal_pwma_handle_t *handle);

当前实现会同时:

AUDIO_CON.DMA_EN = 1
AUDIO_CON.CNT_EN = 1
state = ACTIVE

调用方必须事先启动外部 PDMA,否则可能发生 underrun/empty。使用 CPU 模式时,应在 start 前/后通过 hal_pwma_configure_dma(false) 明确关闭 DMA request。

4.2 hal_pwma_stop

error_code_t hal_pwma_stop(hal_pwma_handle_t *handle);

只关闭 CNT_EN 并回到 READY,不自动关闭 DMA_EN。外部 PDMA 和 DMA request 清理由 上层决定。

4.3 hal_pwma_clear_fifo

error_code_t hal_pwma_clear_fifo(hal_pwma_handle_t *handle);

写 AUDIO_CON.CLR=1,清除内部 FIFO 并终止当前 waveform。

4.4 hal_pwma_clear_first_wave_flag

error_code_t hal_pwma_clear_first_wave_flag(
    hal_pwma_handle_t *handle);

写 1 清除 AUDIO_ST.FST_WAVE。

4.5 Software reset

error_code_t hal_pwma_soft_reset(hal_pwma_handle_t *handle);
error_code_t hal_pwma_clear_soft_reset_status(
    hal_pwma_handle_t *handle);

hal_pwma_soft_reset() 将低有效 SOFT_RESET 拉低再恢复,复位所有 PWMA 配置,并把 handle state 置 RESET。后续必须重新调用 hal_pwma_init()。

4.6 hal_pwma_get_status

error_code_t hal_pwma_get_status(
    const hal_pwma_handle_t *handle,
    hal_pwma_status_t *status_out);

一次读取 AUDIO_ST、AUDIO_CON 和 SOFT_RESET_STATUS,填充 status snapshot。

4.7 Module clock 与 format 转换

error_code_t hal_pwma_get_module_clock_hz(
    const hal_pwma_handle_t *handle,
    uint32_t *rate_hz_out);

error_code_t hal_pwma_format_to_sample_rate(
    hal_pwma_format_t format,
    uint32_t *sample_rate_hz_out);

module clock 是 init 时读回的实际 CGU rate。CPM stub 下返回请求值。

5. HAL DMA、诊断和中断

5.1 DMA data address

error_code_t hal_pwma_get_dma_data_addr(
    const hal_pwma_handle_t *handle,
    void **addr_out);

返回 DMA_DATA 寄存器地址。PDMA 地址转换、buffer 和 descriptor 由上层管理。

5.2 Register dump

error_code_t hal_pwma_regs_dump(
    const hal_pwma_handle_t *handle);

仅在 SDK 和 PWMA debug helper 均启用时可用。默认跳过 DMA_DATA。

5.3 Callback 和 user data

error_code_t hal_pwma_callback_register(
    hal_pwma_handle_t *handle,
    hal_pwma_callback_id_t callback_id,
    hal_pwma_callback_t callback);

error_code_t hal_pwma_user_data_set(
    hal_pwma_handle_t *handle,
    void *user_data);

callback 在 PWMA IRQ context 执行,不得阻塞或 sleep。callback 进入前对应 interrupt source 已被 mask。

5.4 IRQ handler

void hal_pwma_irq_handler(hal_pwma_handle_t *handle);

处理顺序:

  1. 若 first-wave 未 mask 且 FST_WAVE=1,mask source、写 1 清除 FST_WAVE。
  2. 若 DMA-empty 未 mask 且 DMA_FE=1,mask source。
  3. 分别调用 DMA-empty 和 first-wave callback。

DMA empty 是 level-sensitive,mask 是当前实现消除重复中断的方式。需要后续事件时, client 必须重新 unmask。

6. 典型调用流程

6.1 HAL DMA 初始化

hal_pwma_handle_t pwma;
hal_pwma_init_t init;

hal_pwma_handle_init(&pwma, PWMA);
hal_pwma_struct_init(&init);
init.data_type = HAL_PWMA_DATA_SIGNED;
init.endian = HAL_PWMA_ENDIAN_LITTLE;
init.precision = HAL_PWMA_PRECISION_16BIT;
init.format = HAL_PWMA_FORMAT_16K;
init.module_clock_hz = 200000000U;
init.prescaler = 0U;
init.period_threshold = 4168U;
init.high_threshold = 0U;
init.volume_gain = 10U;
init.volume_down = false;
init.dma_enable = true;
init.first_wave_interrupt_masked = true;
init.dma_fifo_empty_interrupt_masked = true;

hal_pwma_init(&pwma, &init);

随后由 Audio middleware/平台代码创建 PDMA,把最后一个 destination 指向:

void *dma_target;
hal_pwma_get_dma_data_addr(&pwma, &dma_target);

6.2 DMA 播放

hal_pwma_start(&pwma);
/* External DMA streams PCM samples to DMA_DATA. */
hal_pwma_stop(&pwma);
hal_pwma_deinit(&pwma);

外部 DMA 应在 hal_pwma_stop() 前后由上层按 transport 顺序停止。HAL stop 不停止 外部 DMA channel。

6.3 CPU 模式

hal_pwma_timing_config_t timing = {
    .prescaler = 0U,
    .period_threshold = 625U,
    .high_threshold = 125U,
};

hal_pwma_configure_timing(&pwma, &timing);
hal_pwma_configure_dma(&pwma, &(hal_pwma_dma_config_t){
    .dma_enable = false,
});
hal_pwma_apply_update(&pwma);
hal_pwma_start(&pwma);
hal_pwma_configure_dma(&pwma, &(hal_pwma_dma_config_t){
    .dma_enable = false,
});

最后再次关闭 DMA 是因为当前 hal_pwma_start() 会无条件置位 DMA_EN。

6.4 运行中修改音量

hal_pwma_volume_config_t volume = {
    .volume_down = true,
    .volume_gain = 0x0FU,
};

hal_pwma_configure_volume(&pwma, &volume);
hal_pwma_apply_update(&pwma);

音量更新与 stop/reconfigure 必须由业务层串行化。