你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32L0系列ADC的低功耗模式AUTOFF和WAIT功能的使用疑惑

[复制链接]
iPeanut 提问时间:2022-1-2 19:13 / 未解决
阅读主题, 点击返回1楼
收藏 评论28 发布时间:2022-1-2 19:13
28个回答
iPeanut 回答时间:2022-1-6 11:22:24
iPeanut 回答时间:2022-1-6 11:23:03

1.在我的第一种应用场景中,需要长时间停留在STOP里时,进入STOP前确实按照手册介绍的那个顺序执行的,但是在退出STOP时,并没有作循环等待REGLPF=0的操作,因为在看HAL库和LL库的例程里并没有看到等待这个标志位的操作所以忽略了,请问REGLPF位恢复为0大概需要多少时间?我用外部中断退出STOP时,中断回调函数入口的大概有4-5条语句执行后(系统时钟16MHz),这个时长是否足够保证REGLPF位恢复为0呢?也就是利用执行语句的延时是否可以保证后面的程序运行可靠呢? 2.在我的第二种低功耗应用场景中,需要用LPTIM定时唤醒STOP,LPTIM的定时中断周期大约为4ms,在该中断中执行ADC采样操作,读取采样数据后就执行停止转换ADSTP=1,并将ADEN清0使ADC关闭(虽然我配置AUTOFF=1,但也执行了这个关闭动作),但不执行关闭ADC调压器的操作,退出中断后回到主循环,然后进入STOP等待下一个定时中断的到来。外部中断唤醒STOP后,也不执行开启ADC的调压器操作。主要是不想在反复开关ADC调压器上占用过多的等待时间,所以始终没执行ADVREGEN清0的操作。请问我这种不关闭ADC调压器就进入STOP的操作方式可靠吗?

iPeanut 回答时间:2022-1-6 11:28:16
iPeanut 回答时间:2022-1-6 11:28:35

butterflyspring 发表于 2022-1-5 17:21
手册中关于AUTOFF 和 WAIT 介绍中提到,只要读取转换值后,再次触发就可以继续转换,并且后面有示意图
楼主 ...

很感谢您的回复,很有帮助。又去看了手册确实如您所说。但又增加了新的疑问:1.在我的第一种应用场景中,需要长时间停留在STOP里时,进入STOP前按照手册介绍的那个顺序执行的,但在退出STOP时,并没有作循环等待REGLPF为0的操作,因为在HAL库和LL库的例程里并没有看到等待这个标志位的操作所以忽略了,请问REGLPF位恢复为0大概需要多少时间?我用外部中断退出STOP时,中断回调函数入口大概有4-5条语句执行后(系统时钟16MHz),这个时长是否足够保证REGLPF位恢复为0呢?也就是利用执行语句的延时是否可以保证后面的程序运行可靠呢? 2.在我的第二种低功耗应用场景中,需要用LPTIM定时唤醒STOP,LPTIM的定时中断周期大约为4ms,在该中断中执行ADC采样操作,读取采样数据后就执行停止转换ADSTP=1,并将ADEN清0使ADC关闭(虽然我配置AUTOFF=1,但也执行了这个关闭动作),但不执行关闭ADC调压器的操作,退出中断后回到主循环,然后进入STOP等待下一个定时中断的到来。外部中断唤醒STOP后,也不执行开启ADC的调压器操作。主要是不想在反复开关ADC调压器上占用过多的等待时间,所以始终没执行ADVREGEN清0的操作。请问我这种不关闭ADC调压器就进入STOP的操作方式可靠吗?

iPeanut 回答时间:2022-1-6 11:30:26
iPeanut 回答时间:2022-1-6 11:31:09

增加了新的疑问:1.在我的第一种应用场景中,需要长时间停留在STOP里时,进入STOP前按照手册介绍的那个顺序执行的,但在退出STOP时,并没有作循环等待REGLPF为0的操作,因为在HAL库和LL库的例程里并没有看到等待这个标志位的操作所以忽略了,请问REGLPF位恢复为0大概需要多少时间?我用外部中断退出STOP时,中断回调函数入口大概有4-5条语句执行后(系统时钟16MHz),这个时长是否足够保证REGLPF位恢复为0呢?也就是利用执行语句的延时是否可以保证后面的程序运行可靠呢?2.在我的第二种低功耗应用场景中,需要用LPTIM定时唤醒STOP,LPTIM的定时中断周期大约为4ms,在该中断中执行ADC采样操作,读取采样数据后就执行停止转换ADSTP=1,并将ADEN清0使ADC关闭(虽然我配置AUTOFF=1,但也执行了这个关闭动作),但不执行关闭ADC调压器的操作,退出中断后回到主循环,然后进入STOP等待下一个定时中断的到来。外部中断唤醒STOP后,也不执行开启ADC的调压器操作。主要是不想在反复开关ADC调压器上占用过多的等待时间,所以始终没执行ADVREGEN清0的操作。请问我这种不关闭ADC调压器就进入STOP的操作方式可靠吗?

iPeanut 回答时间:2022-1-6 11:39:24
iPeanut 回答时间:2022-1-6 11:40:09

增加了新的疑问: 1.在第一种场景中,需要长时间停留在STOP中,进入STOP前按照手册的那个顺序执行的,但在退出STOP时,并没有作循环等待“REGLPF=0”的操作,因为在库函数的例程里并没有看到等待这个位的操作所以忽略了,请问“REGLPF”位恢复为0大概需要多少时间?我用外部中断退出STOP时,中断回调函数入口大概有4到5条语句执行后(系统时钟16MHz),这个时长是否足够保证“REGLPF”位恢复为0呢?也就是利用执行语句的延时是否可以保证后面的程序运行可靠呢? 2.在第二种低功耗应用场景中,需要用LPTIM定时唤醒STOP,LPTIM的定时中断周期大约为4ms,在该中断回调函数中执行ADC采样操作,读取采样数据后就执行停止转换ADSTP=1,并将ADEN清0使ADC关闭(虽然我配置AUTOFF=1,但也执行了这个关闭动作),但不执行关闭ADC调压器的操作,退出中断后回到主循环,然后进入STOP等待下一个定时中断的唤醒到来。因为进入前没有手动关闭ADC调压器,所以外部中断唤醒STOP后,也不执行开启ADC的调压器操作。主要是不想在反复开关ADC调压器上占用过多的等待时间,所以始终没执行ADVREGEN清0的操作。请问我这种不关闭ADC调压器就进入STOP的操作方式可靠吗?

iPeanut 回答时间:2022-1-6 11:40:27
xmshao 回答时间:2022-1-6 12:08:52
你写的很多很详细,涉及细节还是很多的。这里逐一跟你交流下。


1、手册上介绍ADC有个低功耗模式,配置寄存器将AUTOFF=1和WAIT=1,可以让ADC在转换完成后自动关闭,再次触发时会自动开启,可以有效降低功耗。我将这两位功能使能后,发现每次想开启采样,若采用LL库函数LL_ADC_Enable()将ADEN位置1后,是无法等到ADRDY位被置1的,也就是ADRDY始终是0,但是如果不给ADEN置1,直接用LL_ADC_REG_StartConversion()函数给ADSTART位置1,让ADC开始转换,也是可以正常开始的,读到的ADC结果也正常。想问一下这是不是就是AUTOFF和WAIT产生的效果,那么在使用中,只要使能这两位,每次开启ADC采样的时候,直接使能开始ADSTART=1就可以了,不用再让ADEN=1,这样对吗?


===》这样没有什么问题,你的ADSART指令即可开启ADC转换,当然硬件会自动插入启动稳定时间,达到ADEN=1,ADRDY=1的效果。在AUTOFF=1和WAIT=1的情况下,软件启动或硬件触发或对ADC_DR的访问都可以启动ADC转换。


2、结合第1个问题,我使用的cubeMX的LL库生成的ADC初始化函数,其中将AUTOFF=1,WAIT=1,上电后,运行完该初始化函数后,使用了校准功能,调用了LL_ADC_StartCalibration(ADC1)进行校准,调试发现,执行完该校准,再延时几个时钟周期后,ADC好像就已经可以正常工作,也是没有ADEN=1的情况下,直接让ADSTART=1,ADC就可以采集到正确数据了。


===》这个其实跟第一个问题是一样的。尽管校准后理应进入ADC的power off状态,但ADSTART=1还是可以开启ADC转换。这里顺便说下,当我们将ADC配置在AUTOFF状态时,硬件会无视ADRDY标志的,而且会始终保持0状态,也就是上面你提到过的它始终为0的情形.



3、我看到手册中有这样一个描述:启动校准(将ADCAL置1)时,或者使能ADC时(将ADEN置1),ADVREGEN位通过硬件被置1。也就是说执行了校准操作后ADC的调压器被使能了,且又被配置成了AUTOFF=1和WAIT=1的模式,那么在调压器使能的状态下,只要执行ADSTART=1就可以正常开始转换了。再结合其他讨论中有人说到如果要在系统进入低功耗模式前将ADC的调压器失能ADVREGEN=0才可以,据此推断,如果系统唤醒后想让ADC恢复正常工作,必须再执行一次校准操作或者执行一次ADEN=1的操作才可以。我在调试中在进入芯片的STOP模式前执行了CLEAR_BIT(ADC1->CR, ADC_CR_ADVREGEN)禁止调压器,在退出STOP模式后,再执行了一次LL_ADC_StartCalibration(ADC1)的校准操作,ADC都可以恢复正常采集数据。请教一下我的上述操作是否正确可靠?


===》没有什么不可靠。首先,即使你关闭了ADC voltage regulator,当我们进行ADC校准时硬件会自动开启之。校准后即可直接使用ADSTART=1来开启ADC转换,当然此时还是基于你说到的AUTOFF=1模式。


4、虽然手册中介绍说AUTOFF和WAIT使能后ADC可以在采集后自动关闭,但我想尽快降低功耗,所以每次读取到序列最后一个数据后,都再执行一次ADSTP=1和ADDIS=1的操作。我的设计采用的是定时器中断里进行一次ADC采样的方式,每次中断里采样完毕还必执行一次LL_ADC_REG_StopConversion(ADC1)让ADSTP=1使ADC停止,然后再必执行一次LL_ADC_Disable(ADC1)让ADDIS=1使ADC关闭,而下次中断进入时,也是不执行ADEN=1,直接让ADSTART=1,等待ADC获得正确的采样值。


===》你的这些操作没有啥问题,也没看出有啥隐患。你没必要自己手动执行ADSTP=1和ADDIS=1操作了,硬件会自动完成。
iPeanut 回答时间:2022-1-6 15:23:11

xmshao 发表于 2022-1-6 12:08
你写的很多很详细,涉及细节还是很多的。这里逐一跟你交流下。</p>
<p>

感谢您的回复,很有帮助。我想补充请教您一个问题:我在CubeMX的ADC相关配置中并没有使用DMA功能,但是自动生成的LL库初始化函数中却出现了ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_LIMITED;这样一条语句,如果用生成HAL库的初始化函数就不会有这个问题,这是什么原因造成的?我用的CubeMX版本是4.27不知道是不是这个版本的问题。在使用中,在LL库初始化函数中有LL_ADC_REG_DMA_TRANSFER_LIMITED的情况下,我没去管它,仍然当成没有DMA的方式在使用,每次一个通道采集完成后使用函数LL_ADC_IsActiveFlag_EOC(ADC1)等待EOC=1,然后用LL_ADC_REG_ReadConversionData12(ADC1)函数读取ADC DR中的数据,都能正常获得数据。请问这样的配置状态下,这样使用是否正确可行呢???谢谢

iPeanut 回答时间:2022-1-6 15:29:51

xmshao 发表于 2022-1-6 12:08
你写的很多很详细,涉及细节还是很多的。这里逐一跟你交流下。</p>
<p>

感谢感谢,再请教一下,我的设计中有两种进入STOP的应用场景。 1.在第一种场景中,需要长时间停留在STOP中,进入STOP前按照手册的那个顺序执行的,但在退出STOP时,并没有作循环等待“REGLPF=0”的操作,因为在HAL库和LL库函数的例程里并没有看到等待这个位的操作所以忽略了,请问“REGLPF”位恢复为0大概需要多少时间?我用外部中断退出STOP时,中断回调函数入口大概有4到5条语句执行后(系统时钟16MHz),这个时长是否足够保证“REGLPF”位恢复为0呢?也就是利用执行语句的延时是否可以保证后面的程序运行可靠呢? 2.在第二种低功耗应用场景中,需要用LPTIM定时唤醒STOP,LPTIM的定时中断周期大约为4ms,在该中断回调函数中执行ADC采样操作,读取采样数据后就执行停止转换ADSTP=1,并将ADEN清0使ADC关闭(虽然我配置AUTOFF=1,但也执行了这个关闭动作),但不执行关闭ADC调压器的操作,退出中断后回到主循环,然后进入STOP等待下一个定时中断的唤醒到来。因为进入前没有手动关闭ADC调压器,所以外部中断唤醒STOP后,也不执行开启ADC的调压器操作。主要是不想在反复开关ADC调压器上占用过多的等待时间,所以始终没执行ADVREGEN清0的操作。请问我这种不关闭ADC调压器就进入STOP的操作方式可靠吗? 3.我配置的是ULP=1且FWU=1的快速唤醒方式,按照说明退出低功耗模式是忽略VREFINT,但VREFINT不稳定会影响ADC,我第二种应用场景中,中断唤醒后在执行开始ADC前会有一些执行语句,用这些执行语句的延时是否可以保证VREFINT稳定?而且我采用的是AUTOFF=1WAIT=1的模式,每次唤醒中断回调函数中开始ADC采样的时候,只发送ADSTART=1然后等待转换结束标志去读数据,这种使用方式是否可以保证VREFINT已经稳定,ADC获得稳定数据呢

butterflyspring 回答时间:2022-1-7 11:14:40
iPeanut 发表于 2022-1-6 15:23
[md]感谢您的回复,很有帮助。我想补充请教您一个问题:我在CubeMX的ADC相关配置中并没有使用DMA功能,但 ...

我用6.30版本的cubemx去配置的话,没有配置DMA的话,结果是“ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;”。 如果楼主的配置中与DMA相关的都没有,那就有可能与版本相关。还需要仔细核对。
从楼主的描述看,似乎配置了ADC的DMA的项,使得DMA发出request。 但是和DMA外设的配置没有配的话,就相当于DMA没有工作,所以运行起来跟没有DMA的方式一样。
iPeanut 回答时间:2022-1-7 15:22:58

butterflyspring 发表于 2022-1-7 11:14
我用6.30版本的cubemx去配置的话,没有配置DMA的话,结果是“ADC_REG_InitStruct.DMATransfer = LL_ADC_R ...

感谢您的回复,在我的设计中串口收发配置使用了DMA,但ADC在CubeMX中配置确实没使用DMA,但LL库自动生成了ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_LIMITED;在ADC使用中也始终没有对他的转换作任何DMA的配置操作,这是不是就是您所说的相当于DMA没有工作呢?下面是我的自动生成的ADC初始化函数。是否会有问题吗?

void MX_ADC_Init(void) { LL_ADC_REG_InitTypeDef ADC_REG_InitStruct; LL_ADC_InitTypeDef ADC_InitStruct;

LL_GPIO_InitTypeDef GPIO_InitStruct; / Peripheral clock enable / LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);

/*ADC GPIO Configuration PA2 ------> ADC_IN2 PA3 ------> ADC_IN3 / GPIO_InitStruct.Pin = LL_GPIO_PIN_2; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_3; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/*Configure Regular Channel / LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_2);

/*Configure Regular Channel / LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_3);

/*Configure Regular Channel / LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_VREFINT);

LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_PATH_INTERNAL_VREFINT);

/*Common config / ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE; ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE; ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE; ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_LIMITED;//注意此处被初始化成了有DMA ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN; LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);

LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_39CYCLES_5);

LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE);

LL_ADC_SetCommonFrequencyMode(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CLOCK_FREQ_MODE_LOW);

LL_ADC_DisableIT_EOC(ADC1);

LL_ADC_DisableIT_EOS(ADC1);

ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B; ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT; ADC_InitStruct.LowPowerMode = LL_ADC_LP_AUTOWAIT_AUTOPOWEROFF; LL_ADC_Init(ADC1, &ADC_InitStruct);

LL_ADC_SetClock(ADC1, LL_ADC_CLOCK_ASYNC);

LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CLOCK_ASYNC_DIV2);

}

12
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版