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);
执行顺序:
- 校验配置。
- 设置 CPM
CGU_PWMArate,并打开 PWMA gate。 - 读回实际 module clock。
- 关闭 waveform output。
- 配置 input、timing、levels、volume、interrupt 和 DMA request。
- 写
AUDIO_UPDATE。 - 进入 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);
处理顺序:
- 若 first-wave 未 mask 且
FST_WAVE=1,mask source、写 1 清除 FST_WAVE。 - 若 DMA-empty 未 mask 且
DMA_FE=1,mask source。 - 分别调用 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 必须由业务层串行化。