
STM32F373 SDAC1+DMA,数据只能更新一次?
关于stm32g030f6p6 adc3个值问题 temp vrefint vbat
STM32 双ADC同步注入转换模式,模块ADC2没有数据。
STM32G0B1adc+dma采样数据错位
STM32H743+USB3300传输采集的数据前几次会丢包问题
H750/743 VREFBUF配置问题
stmL5系列,HAL库如何设置Lpuart APB clock domain
为什么STM32L496RG第一次烧写程序后需要重新上下电才能正常执行程序?
关于STM32F4的ADC测量不准确
与HAL_ADC_Start_DMA相关的一个十分怪异的问题
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的操作方式可靠吗?
很感谢您的回复,很有帮助。又去看了手册确实如您所说。但又增加了新的疑问: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的操作方式可靠吗?
增加了新的疑问: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的操作方式可靠吗?
增加了新的疑问: 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的操作方式可靠吗?
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操作了,硬件会自动完成。
感谢您的回复,很有帮助。我想补充请教您一个问题:我在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中的数据,都能正常获得数据。请问这样的配置状态下,这样使用是否正确可行呢???谢谢
感谢感谢,再请教一下,我的设计中有两种进入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获得稳定数据呢
我用6.30版本的cubemx去配置的话,没有配置DMA的话,结果是“ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;”。 如果楼主的配置中与DMA相关的都没有,那就有可能与版本相关。还需要仔细核对。
从楼主的描述看,似乎配置了ADC的DMA的项,使得DMA发出request。 但是和DMA外设的配置没有配的话,就相当于DMA没有工作,所以运行起来跟没有DMA的方式一样。
感谢您的回复,在我的设计中串口收发配置使用了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);
}