华大HDL136X芯片adc用dma方式进行采样
发布日期:2021-05-13 00:02:51 浏览次数:20 分类:精选文章

本文共 5268 字,大约阅读时间需要 17 分钟。

Âu preferably, a technical writer would approach it like this:

In our project, we are using the ADC on a certain chip that is somewhat similar to the STM32 series in terms of DMA-based sampling mechanism. However, there has been an observation regarding the software trigger behavior on this chip compared to STM32. Unlike STM32 where the ADC can be left to continuously convert unless stopped, this chip's ADC needs to be manually restarted after each conversion, making the process somewhat less seamless. This is particularly noticeable because after each conversion completes, if we want to continue sampling, we have to manually initiate the next conversion within the interrupt handler.

While the specifics of the hardwaredatepicker can vary, the general workflow is similar. Let's take a closer look at how the ADC is initialized and managed in our system.

First, the GPIO configuration is essential for setting up the ADC pins properly. In our implementation, we have configured specific GPIO pins on Port A and Port B to operate in analog mode, which is a necessary step before enabling the ADC module.

Next, the ADC module itself requires careful configuration. We need to set the operating mode, sampling frequency, and other parameters such as reference voltage selection and alignment. The following code snippet illustrates the ADC configuration process:

static void Adc_Config(void) {
stc_adc_cfg_t stcAdcCfg;
stc_adc_sqr_cfg_t stcAdcSqrCfg;
// Initialize structs to default values
DDL_ZERO_STRUCT(stcAdcCfg);
DDL_ZERO_STRUCT(stcAdcSqrCfg);
// Enable the ADC/BGR clock
Sysctrl_SetPeripheralGate(SysctrlPeripheralAdcBgr, TRUE);
Bgr_BgrEnable();
// Configure ADC parameters
stcAdcCfg.enAdcMode = AdcScanMode; // Set to scanning mode
stcAdcCfg.enAdcClkDiv = AdcMskClkDiv1; // Use a specific clock division
stcAdcCfg.enAdcSampCycleSel = AdcMskSampCycle8Clk; // Select 8 cycles
stcAdcCfg.enAdcRefVolSel = AdcMskRefVolSelAVDD; // Use VCC as reference voltage
stcAdcCfg.enAdcOpBuf = AdcMskBufDisable; // Disable OP buffer
stcAdcCfg.enInRef = AdcMskInRefDisable; // Disable internal reference
stcAdcCfg.enAdcAlign = AdcAlignRight; // Align results to the right
// Initialize ADC with the configuration
Adc_Init(&stcAdcCfg);
// Clear and enable ADC squaring channel interrupts
Adc_CfgSqrChannel(AdcSQRCH0MUX, AdcExInputCH0);
Adc_CfgSqrChannel(AdcSQRCH1MUX, AdcExInputCH1);
// ... and so on for all channels
Adc_CfgSqrChannel(AdcSQRCH9MUX, AdcExInputCH9);
// Enable ADC interrupts and NVIC
Adc_EnableIrq();
EnableNvic(ADC_IRQn, IrqLevel3, TRUE);
// Start the ADC squaring process
Adc_SQR_Start();
}

One notable aspect of our implementation is the handling of ADC interrupts. After each conversion completes, the interrupt serviceroutine (ISR) is triggered. Within the ISR, we not only clear the interrupt status but also reinitialize the ADC to continue sampling:

void ADC_IRQHandler(void) {
if (TRUE == Adc_GetIrqStatus(AdcMskIrqSqr)) {
Adc_ClrIrqStatus(AdcMskIrqSqr);
Adc_SQR_Start(); // Restart the ADC conversion
}
}

This approach ensures that the ADC is always available for the next conversion as soon as it completes one. However, it's worth noting that this manual restart is a common practice in embedded systems when dealing with continuous sampling.

Moving on to the DMA configuration, we have implemented a solution to offload the data transfer from the ADC to the external storage or processing units. The DMA is set up to handle the transfer of data in a block-wise manner, which is particularly useful when dealing with multiple channels or a high number of samples:

static void Dma_Config(void) {
stc_dma_cfg_t stcDmaCfg;
DDL_ZERO_STRUCT(stcDmaCfg);
// Enable DMAC clock
Sysctrl_SetPeripheralGate(SysctrlPeripheralDma, TRUE);
// Set source and destination addresses
stcDmaCfg.u32SrcAddress = 0x40002450;
stcDmaCfg.u32DstAddress = (uint32_t)ADC_DATA.Conversion_Value;
// Configure DMA to use block transfer mode
stcDmaCfg.enTransferMode = DmaMskContinuousTransfer;
stcDmaCfg.enDestAddrMode = DmaMskDstAddrInc;
stcDmaCfg.enSrcAddrMode = DmaMskSrcAddrInc;
// Set block size and transfer count
stcDmaCfg.u16BlockSize = 10;
stcDmaCfg.u16TransferCnt = 1;
stcDmaCfg.enMode = DmaMskBlock;
stcDmaCfg.enTransferWidth = DmaMsk32Bit;
// Set the priority and trigger source
stcDmaCfg.enPriority = DmaMskPriorityFix;
stcDmaCfg.enRequestNum = DmaADCSQRTrig;
// Enable DMAC and initialize the channel
Dma_Enable();
Dma_InitChannel(DmaCh0, &stcDmaCfg);
Dma_EnableChannel(DmaCh0);
}

Finally, the ADC initialization function ties all these configurations together:

void ADC_Init(void) {
Adc_Gpio_Config();
Adc_Config();
Dma_Config();
}

In summary, while our approach to ADC sampling is aligned with the principles of STM32, the implementation details differ slightly, particularly in how the ADC is managed and interrupted. The key takeaway is that the ADC needs to be manually restarted after each conversion, making it essential to integrate this behavior into the main application loop or ISR to ensure continuous sampling.

上一篇:端子型号,PH,XH,ZH,EH,VH
下一篇:ARM Compiler 6 优化等级

发表评论

最新留言

感谢大佬
[***.8.128.20]2025年04月08日 00时53分35秒