HPM5300系列MCU是上海先楫半导体推出的一款高性能RISC-V内核通用微控制器。
HPM5300系列RISC-VCPU主频高达480MHz,内置288KBSRAM和1MB Flash,并提供48~100脚LOFP和OFN等封装,为工业自动化,新能源及汽车等应用提供了丰富的算力和高效的控制能力。
HPM5300EVK提供了一系列HPM5300微控制器外设的接口,包括一个ADC输入SMA接口和一个先楫标准的电机控制及传感器接口。HPM5300EVK同时集成了1个2x20 pin IO扩展接口,连接了HPM5300 MCU的大部分IO,供用户自由评估。HPM5300EVK集成了板载调试器,同时提供了一个标准JTAG接口可以连接JLINK、DAPLINK等调试器。
可以通过依次配置 SEQ_QUE0 到 SEQ_QUE15 寄存器来指定转换序列的目标输入通道。SEQ_QUE0 [CHAN_NUM] 位域用于配置序列转换触发后的第一次转换的通道序号,SEQ_QUE1 [CHNUM] 位域配置第二次转换的通道序号,以此类推,SEQ_QUE15 [CHNUM] 位配置第16次转换的通道序号。此外,需要配置 SEQ_CFG0 [SEQ_LEN] 位来指定转换序列的长度,ADC的转换序列最长可达16个通道。序列的开始转换可以通过软件或硬件触发实现:
通过软件触发:首先将 SEQ_CFG0 [SW_TRIG_EN] 位置1,然后将 SEQ_CFG0 [SW_TRIG] 位置1,即可触发序列转换。
通过硬件触发:将 SEQ_CFG0 [HW_TRIG_EN] 位置1,当触发引脚(STRGI)上检测到上升沿时,即可触发序列转换。
一旦触发,ADC将按照顺序根据 SEQ_QUE0 的配置开始转换输入通道。转换完成后,标志位 INT_STS [SEQ_CVC](转换完成)将被置为1。此时:
如果 SEQ_CFG0 [CONT_EN] 位置1,ADC将自动根据 SEQ_QUE1 的配置开始下一次转换,直到达到指定的序列长度 SEQ_QUEn。
如果 SEQ_CFG0 [CONT_EN] 位清零,ADC将等待下一次软件或硬件触发才会开始下一个通道的转换。
当ADC完成整个序列的转换(长度由 SEQ_CFG0 [SEQ_LEN] 位设置)后,标志位 INT_STS [SEQ_CMPT](序列转换完成)将被置为1。此时:
如果 SEQ_CFG0 [RESTART_EN] 位置1且 SEQ_CFG0 [CONT_EN] 位置1,ADC将自动根据 SEQ_QUEx 的配置,从 SEQ_QUE0 开始连续依次转换。
如果 SEQ_CFG0 [RESTART_EN] 位置0且 SEQ_CFG0 [CONT_EN] 位置1,ADC将在下一次软件或硬件触发后连续转换直到整个序列完成。
如果 SEQ_CFG0 [CONT_EN] 位置0,无论 SEQ_CFG0 [RESTART_EN] 位置1还是0,ADC将在下一次软件或硬件触发后重新根据 SEQ_QUEx 的配置开始转换。
如果在ADC序列转换过程中接收到新的序列转换触发信号,ADC将忽略该触发。如果是通过软件触发序列转换,INT_STS [SEQ_SW_CFLCT] 位将被置为1。如果是由 STRGI 引发的硬件触发序列转换,INT_STS [SEQ_HW_CFLCT] 位将被置为1。
ADC序列转换模式支持内置DMA,可以直接将转换结果写入用户指定的内存缓冲区。用户可以通过 SEQ_DMA_ADDR 寄存器配置目标地址,并通过 SEQ_DMA_CFG [BUF_LEN] 设置数据区域的长度,从而为ADC的序列转换结果配置一个循环缓冲区。
抢占转换模式:
ADC支持抢占转换模式,这是优先级最高的转换模式,适用于对电机控制系统中实时性要求较高的情况,需要在指定时间对指定通道进行转换。
ADC支持12组抢占转换序列,触发信号来自芯片的片上互联模块,共有12个抢占触发源。这些抢占转换序列可以通过寄存器CONFIGx进行配置。抢占转换是通过硬件触发实现的,当PTRGIxA、PTRGIxB或PTRGIxC上出现上升沿时,会触发相应的抢占序列xA、xB或xC。首先,用户需要通过CONFIGx寄存器的[TRIG_LEN]位来配置抢占转换的序列长度,最多可以设置为4,即每个触发最多可以触发一次长度为4的转换。可以通过CONFIGx寄存器配置抢占转换的转换顺序。通过配置寄存器的[CHAN0]、[CHAN1]、[CHAN2]和[CHAN3]位域,依次配置触发后的第1、2、3、4次转换的AD输入通道号码。
一旦抢占转换开始,ADC会根据[TRIG_LEN]的配置连续进行转换,完成整个抢占序列。在抢占序列的第x次转换完成后,如果CONFIGx寄存器的[INTENx]位置为1,INT_STS[TRIG_CMPT]标志位会被置为1。如果相应的中断控制位也被置为1,ADC会生成中断。在ADC抢占转换过程中,如果接收到新的抢占转换触发信号,ADC不会响应新的触发。但是,根据触发源是软件还是硬件,INT_STS[TRIG_SW_CFLICT]标志位或INT_STS[TRIG_HW_CFLICT]标志位会被置为1,表示发生了抢占转换触发冲突。如果对应的中断控制位也被置为1,ADC会产生中断报警。
如果多个不同的抢占转换同时触发,ADC会按照以下优先顺序进行响应:较小组号的抢占转换优先,例如PTRGI0A优先于PTRGI1A;同一组中,xA优先于xB,xB优先于xC,例如PTRGI0A优先于PTRGI0B。同时,INT_STS[PTCHWCFLICT]标志位会被置为1。
ADC抢占转换模式也支持内置DMA,可以直接将转换结果写入用户指定的内存缓冲区中。
测试代码及过程:
首先是硬件初始化和配置时钟,这里我们的程序采用ADC0的11通道进行测试,查看芯片的数据手册可以看到ADC0_IN11所在端口是在PB08
复制
int main(void)
{ uint8_t conv_mode;
board_init();
board_init_adc16_pins();
board_init_adc16_clock(BOARD_APP_ADC16_BASE, true);
printf("This is an ADC16 demo:\n");
conv_mode = get_adc_conv_mode();
init_common_config(conv_mode);
switch (conv_mode) {
case adc16_conv_mode_oneshot:
init_oneshot_config(); break;
case adc16_conv_mode_period:
init_period_config(); break;
case adc16_conv_mode_sequence:
init_sequence_config(); break;
case adc16_conv_mode_preemption:
init_preemption_config(); break;
default:
break;
}
while (1) {
board_delay_ms(1000);
channel_result_out_of_threshold_handler(); if (conv_mode == adc16_conv_mode_oneshot) {
oneshot_handler(); } else if (conv_mode == adc16_conv_mode_period) {
period_handler(); } else if (conv_mode == adc16_conv_mode_sequence) {
sequence_handler(); } else if (conv_mode == adc16_conv_mode_preemption) {
preemption_handler(); } else {
printf("Conversion mode is not supported!\n");
} }}
它首先初始化了一些硬件和ADC相关的配置,然后从控制台获取了一个转换模式,并根据不同的转换模式进行不同的初始化操作。接着进入一个主循环,每隔1秒进行一次延时,然后根据不同的转换模式调用不同的处理函数进行处理。如果转换模式不被支持,会输出一个错误信息。整体来说,这段代码是一个ADC16的演示程序,根据不同的转换模式进行不同的处理。
代码总共配置了四种转换模式,根据选择的模式进行初始化
复制
hpm_stat_t init_common_config(adc16_conversion_mode_t conv_mode){ adc16_config_t cfg;
adc16_get_default_config(&cfg); cfg.res = adc16_res_16_bits; cfg.conv_mode = conv_mode; cfg.adc_clk_div = adc16_clock_divider_4; cfg.sel_sync_ahb = (clk_adc_src_ahb0 == clock_get_source(BOARD_APP_ADC16_CLK_NAME)) ? true : false;
if (cfg.conv_mode == adc16_conv_mode_sequence ||
cfg.conv_mode == adc16_conv_mode_preemption) { cfg.adc_ahb_en = true;
}
if (adc16_init(BOARD_APP_ADC16_BASE, &cfg) == status_success) {
intc_m_enable_irq_with_priority(BOARD_APP_ADC16_IRQn, 1);
return status_success;
} else {
printf("%s initialization failed!\n", BOARD_APP_ADC16_NAME);
return status_fail;
}}
采样精度设置为16位,时钟预分频为4分频模式。
这里我只测试了读取转换模式,模式配置和处理函数如下:
复制
void init_oneshot_config(void)
{ adc16_channel_config_t ch_cfg;
adc16_get_channel_default_config(&ch_cfg);
ch_cfg.ch = BOARD_APP_ADC16_CH_1; ch_cfg.sample_cycle = 20;
adc16_init_channel(BOARD_APP_ADC16_BASE, &ch_cfg); adc16_set_nonblocking_read(BOARD_APP_ADC16_BASE);#if defined(ADC_SOC_BUSMODE_ENABLE_CTRL_SUPPORT) && ADC_SOC_BUSMODE_ENABLE_CTRL_SUPPORT
adc16_enable_oneshot_mode(BOARD_APP_ADC16_BASE);#endif
}void oneshot_handler(void)
{ uint16_t result; if (adc16_get_oneshot_result(BOARD_APP_ADC16_BASE, BOARD_APP_ADC16_CH_1, &result) == status_success) {
if (adc16_is_nonblocking_mode(BOARD_APP_ADC16_BASE)) {
adc16_get_oneshot_result(BOARD_APP_ADC16_BASE, BOARD_APP_ADC16_CH_1, &result); } printf("Oneshot Mode - %s [channel %02d] - Result: 0x%04x\n", BOARD_APP_ADC16_NAME, BOARD_APP_ADC16_CH_1, result);
}}
结果处理函数:
复制
hpm_stat_t adc16_get_oneshot_result(ADC16_Type *ptr, uint8_t ch, uint16_t *result)
{ uint32_t bus_res;
if (ADC16_IS_CHANNEL_INVALID(ch)) {
return status_invalid_argument;
} bus_res = ptr->BUS_RESULT[ch]; *result = ADC16_BUS_RESULT_CHAN_RESULT_GET(bus_res);
if (ADC16_BUF_CFG0_WAIT_DIS_GET(ptr->BUF_CFG0)) {
if (!ADC16_BUS_RESULT_VALID_GET(bus_res)) {
return status_fail;
} } return status_success;
}
总的来说先楫HPM5361EVK的ADC功能非常出色!它提供了高精度、高性能和可靠性,能够准确地转换模拟信号为数字数据。其高分辨率和低噪声特性使其在各种应用中表现出色。开发板的两个16位的高精度ADC可以满足大多数实际工程需要,同时四种采样模式也可以满足不同用户的需求,先楫HPM5361EVK开发板值得大家认真了解和测试的一款开发板。