介绍
ADC有四个转换模式:读取转换,周期转换,序列转换,抢占转换
序列转换是可以将几个通道的数据按照顺序逐一去转换, 例如 通道 1 2 3 可以将转换顺序设置为3 1 2,最多一次可以转换十六个通道。序列转换还能通过软件、硬件触发转换与连续转换,将转换数据搬运到DMA中,另外这里的DMA用法也与其他的MCU不同,不需要配置地址自增这些。
配置步骤
● 挂上时钟,复用IO口
board_init_adc_clock(HPM_ADC3, true);
HPM_IOC->PAD[IOC_PAD_PE29].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK;
● 配置精度,ADC时钟分频,模式,同步系统时钟,是否使能数据到DMA
adc16_get_default_config(&config_t);
config_t.res = 21;
config_t.adc_ahb_en =true;
config_t.adc_clk_div = 4U;
config_t.conv_mode = adc16_conv_mode_sequence;
config_t.sel_sync_ahb = (clk_adc_src_ahb0 == clock_get_source(clock_adc3)?true:false);
if(adc16_init(HPM_ADC3,&config_t)!=status_success)
{
printf("ADC3_sequnce Init error\n");
while(1);
}
●配置通道,采样时间
adc16_get_channel_default_config(&channel_config);
channel_config.sample_cycle = 20;
for(int i=0;i<sizeof(seq_adc_channel);i++)
{
channel_config.ch = seq_adc_channel[i];
adc16_init_channel(HPM_ADC3, &channel_config);
}
●配置序列通道数量,序列自动转换,序列硬件转换,序列软件转换,序列转换,序列转换完成后进入是否进入中断
seq_config.seq_len = sizeof(seq_adc_channel);
seq_config.restart_en = false;//不使能自动转换
seq_config.cont_en = true;//使能转换
seq_config.hw_trig_en = true;//使能硬件触发转换
seq_config.sw_trig_en = false;//不使能软件触发
for (int i =0; i<seq_config.seq_len;i++) {
seq_config.queue[i].ch = seq_adc_channel[i];//配置通道
seq_config.queue[i].seq_int_en = false;//不使能本次转换完成后中断
}
seq_config.queue[seq_config.seq_len-1].seq_int_en = true;//最后一个完成后进入中断
adc16_set_seq_config(HPM_ADC3, &seq_config);
●DMA配置,配置DMA搬运内存,内存大小,是否完成DMA进入中断。
dma_config.start_addr = (uint32_t *)core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)seq_buff);
dma_config.buff_len_in_4bytes = sizeof(seq_buff);
dma_config.stop_en = false;
dma_config.stop_pos = 0;
adc16_init_seq_dma(HPM_ADC3, &dma_config);
●设置中断 设置序列转换完成中断,设置抢占优先级
adc16_enable_interrupts(HPM_ADC3, adc16_event_seq_single_complete);
intc_m_enable_irq_with_priority(IRQn_ADC3, 1);
●设置互联管理器,由于我是使用硬件触发ADC序列转换,需要用互联管理器来链接一个硬件触发ADC,这里使用的是PWM。
TRGM_Init(HPM_TRGM0,TRGM_TRGOCFG_ADC3_STRGI,HPM_TRGM0_INPUT_SRC_PWM0_CH8REF);
TRGM_Input_INit(2999);
void TRGM_Init(TRGM_Type *ptr,uint8_t output,uint8_t input)
{
trgm_output_t trgm_config ={0};
trgm_config.input = input;
trgm_config.invert = false;//是否翻转极性
trgm_config.type = trgm_output_same_as_input;//设置输出类型
trgm_output_config(ptr,output,&trgm_config);
}
void TRGM_Input_INit(uint32_t cmp)
{
pwm_cmp_config_t cmp_config[1] ={0};
pwm_config_t config ={0};
pwm_output_channel_t output_config ={0};
pwm_get_default_pwm_config(HPM_PWM0, &config);
config.invert_output = false;
config.enable_output =false;
config.dead_zone_in_half_cycle = 0;
pwm_set_reload(HPM_PWM0, 0, 5999);
pwm_set_start_count(HPM_PWM0, 0, 0);
pwm_get_default_cmp_config(HPM_PWM0,&cmp_config[0]);
cmp_config[0].cmp = cmp;
cmp_config[0].mode = pwm_cmp_mode_output_compare;
cmp_config[0].update_trigger =pwm_shadow_register_update_on_shlk;
if(status_success != pwm_setup_waveform(HPM_PWM0, 8, &config, 1, &cmp_config[0], 1))
{
printf("PWM0 set cmp error\n");
while(0);
}
pwm_issue_shadow_register_lock_event(HPM_PWM0);
pwm_start_counter(HPM_PWM0);
}
中断函数
void isr_adc16(void)
{
uint32_t status = adc16_get_status_flags(HPM_ADC3);//获取状态
adc16_clear_status_flags(BOARD_APP_ADC16_BASE, status);//清除标志位
if (ADC16_INT_STS_SEQ_CVC_GET(status))
seq_complete_flag = 1;
if (ADC16_INT_STS_WDOG_GET(status) & APP_ADC16_CH_WDOG_EVENT)//判断是否是同一个
{
adc16_disable_interrupts(BOARD_APP_ADC16_BASE, APP_ADC16_CH_WDOG_EVENT);
trig_complete_flag = ADC16_INT_STS_WDOG_GET(status)&(1<<2);//取出通道值
}
}
测试
void sequence_handler(void)
{
#if defined(ADC_SOC_NO_HW_TRIG_SRC) || defined(__ADC16_USE_SW_TRIG)
/* SW trigger */
adc16_trigger_seq_by_sw(BOARD_APP_ADC16_BASE);
#endif
while (seq_complete_flag == 0) {
}
/* Process data */
process_seq_data(seq_buff, APP_ADC16_SEQ_START_POS, sizeof(seq_adc_channel));
/* Clear the flag */
seq_complete_flag = 0;
}
hpm_stat_t process_seq_data(uint32_t *buff, int32_t start_pos, uint32_t len)
{
adc16_seq_dma_data_t *dma_data = (adc16_seq_dma_data_t *)buff;
if (ADC16_IS_SEQ_DMA_BUFF_LEN_INVLAID(len)) {//检查序列有效性
return status_invalid_argument;
}
for (uint32_t i = start_pos; i < start_pos + len; i++) {
printf("Sequence Mode - %s - ", BOARD_APP_ADC16_NAME);
printf("Cycle Bit: %02d - ", dma_data[i].cycle_bit);
printf("Sequence Number:%02d - ", dma_data[i].seq_num);
printf("ADC Channel: %02d - ", dma_data[i].adc_ch);
printf("Result: 0x%04x\n", dma_data[i].result);
}
return status_success;
}
main函数
int main(void)
{
/* Bsp initialization */
adc16_config_t config;
board_init();
printf("This is an ADC16 demo:\n");
Sequence_Init();
/* Main loop */
while (1) {
channel_result_out_of_threshold();
sequence_handler();
//sequeue_Handler();
}
}