欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2703|回復: 1
收起左側(cè)

STM32H7 ADC rtthread適配

[復制鏈接]
ID:946949 發(fā)表于 2021-6-29 20:29 | 顯示全部樓層 |閱讀模式
筆記內(nèi)容
        針對RT-Thread官方源碼ADC驅(qū)動中沒有對STM32H7進行支持,本文記錄了對原ADC驅(qū)動進行修改以適配STM32H7的過程。
1.ADC驅(qū)動詳解
        外設驅(qū)動的使用邏輯都大體一致,先是外設初始化,大體包括時鐘初始化、I/O初始化、外設初始化,正確初始化后即可通過外設接口控制外設的工作,對于adc來說就是控制adc的采集,返回采集值。
        H7的adc可配置為 獨立/雙重 ,單/多通道,單次/連續(xù),單端/差分,輪詢/中斷/DMA 采集模式,可以配置的模式比較多,針對需求本文實現(xiàn)了 獨立 單通道 單純 單端的輪詢/中斷/DMA 采集模式。
2.ADC初始化
        RT-Thread使用自動初始化完成ADC的初始化設備注冊,初始化參數(shù)從 adc_config[] 中獲取。
ADC 初始化結構體參數(shù)定義如下(位于adc_config.h):
#define ADC1_CONFIG                                                 \
{                                                               \
       .Instance                   = ADC1,                          \
       .Init.ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV4,      \
       .Init.Resolution            = ADC_RESOLUTION_12B,            \
       .Init.DataAlign             = ADC_DATAALIGN_RIGHT,           \
       .Init.ScanConvMode          = DISABLE,                       \
       .Init.EOCSelection          = DISABLE,                       \
       .Init.ContinuousConvMode    = DISABLE,                       \
       .Init.NbrOfConversion       = 1,                             \
       .Init.DiscontinuousConvMode = DISABLE,                       \
       .Init.NbrOfDiscConversion   = 0,                             \
       .Init.ExternalTrigConv      = ADC_SOFTWARE_START,            \
       .Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE, \
       .Init.DMAContinuousRequests = DISABLE,                       \
}
上述參數(shù)對于H7來說是不適用的,因此需進行以下修改:
#define ADC1_CONFIG                                             \
{                                                               \
    .Instance                   = ADC1,                         \
    .Init.ClockPrescaler        = ADC_CLOCK_ASYNC_DIV1,         \
    .Init.Resolution            = ADC_RESOLUTION_16B,           \
    .Init.ScanConvMode          = ADC_SCAN_DISABLE,             \
    .Init.EOCSelection          = ADC_EOC_SINGLE_CONV,          \
    .Init.LowPowerAutoWait      = DISABLE,                      \
    .Init.ContinuousConvMode    = DISABLE,                      \
    .Init.NbrOfConversion       = 1,                            \
    .Init.DiscontinuousConvMode = DISABLE,                      \
    .Init.ExternalTrigConv      = ADC_SOFTWARE_START,           \
    .Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE,\
    .Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR,     \
    .Init.Overrun               = OVR_DATA_OVERWRITTEN,         \
    .Init.LeftBitShift          = ADC_LEFTBITSHIFT_NONE,        \
    .Init.OversamplingMode      = DISABLE,                      \
}
每個參數(shù)詳解如下:
(1) ClockPrescaler:ADC 時鐘分頻系數(shù)選擇,系數(shù)決定ADC 時鐘頻率,可選的分頻系數(shù)為1、2、4 和6 等。
(2) Resolution:配置ADC 的分辨率,可選的分辨率有16 位、12 位、10 位和8 位。
(3) ScanConvMode:可選參數(shù)為ENABLE 和DISABLE,配置是否使用掃描。如果是單通道AD 轉(zhuǎn)換使用DISABLE,如果是多通道AD 轉(zhuǎn)換使用ENABLE。
(4) EOCSelection:可選參數(shù)為ADC_EOC_SINGLE_CONV 和ADC_EOC_SEQ_CONV ,指定通過輪詢和中斷來使用EOC 標志或者是EOS 標志進行轉(zhuǎn)換。
(5) LowPowerAutoWait:在低功耗模式下,自動調(diào)節(jié)ADC 的轉(zhuǎn)換頻率。
(6) ContinuousConvMode:可選參數(shù)為ENABLE 和DISABLE,配置是啟動自動連續(xù)轉(zhuǎn)換還是單次轉(zhuǎn)換。
(7) NbrOfConversion:指定AD 規(guī)則轉(zhuǎn)換通道數(shù)目,最大值為16。
(8) DiscontinuousConvMode:不連續(xù)采樣模式。一般為禁止模式。
(10) ExternalTrigConv:外部觸發(fā)選擇,一般使用軟件自動觸發(fā)。
(11) ExternalTrigConvEdge:外部觸發(fā)極性選擇,如果使用外部觸發(fā),可以選擇觸發(fā)的極性,可選有禁止觸發(fā)檢測、上升沿觸發(fā)檢測、下降沿觸發(fā)檢測以及上升沿和下降沿均可觸發(fā)檢測。
(12) ConversionDataManagement: ADC 轉(zhuǎn)換后的數(shù)據(jù)處理方式。可以選擇DMA 傳輸,存儲在數(shù)據(jù)寄存器中或者是傳輸?shù)紻FSDM寄存器中。
(13) Overrun:當數(shù)據(jù)溢出時,可以選擇覆蓋寫入或者是丟棄新的數(shù)據(jù)。
(14) LeftBitShift:數(shù)據(jù)左移位數(shù),一般用于數(shù)據(jù)對齊。最多可支持左移15 位。
(16) OversamplingMode:是否使能過采樣模式。
3.ADC 轉(zhuǎn)換
      RT-Thread使用stm32_adc_enabledstm32_adc_get_channel 兩個函數(shù)完成轉(zhuǎn)換,stm32_adc_enabled中進行ADC的使能和關閉操作,在實際測試過程中可不使用, stm32_adc_get_channel  完成ADC 通道配置、輪詢檢查轉(zhuǎn)換狀態(tài)、獲取轉(zhuǎn)換數(shù)據(jù)。
ADC_ChannelConfTypeDef 結構體:
typedef struct {
    uint32_t Channel; /*!< ADC 轉(zhuǎn)換通道*/
    uint32_t Rank; /*!< ADC 轉(zhuǎn)換順序 */
    uint32_t SamplingTime; /*!< ADC 采樣周期 */
    uint32_t SingleDiff; /*!< 輸入信號線的類型*/
    uint32_t OffsetNumber; /*!< 采用偏移量的通道 */
    uint32_t Offset; /*!< 偏移量 */
    FunctionalState OffsetRightShift; /*!< 數(shù)據(jù)右移位數(shù)*/
    FunctionalState OffsetSignedSaturation; /*!< 轉(zhuǎn)換數(shù)據(jù)格式為有符號位數(shù)據(jù) */
} ADC_ChannelConfTypeDef;
(1) Channel:ADC 轉(zhuǎn)換通道?梢赃x擇0~19。
(2) Rank:ADC 轉(zhuǎn)換順序,可以選擇1~16。
(3) SamplingTime:ADC 的采樣周期。
(4) SingleDiff:選擇ADC 輸入信號的類型?梢赃x擇差分或者是單線。如果選擇差分模式,則需要將相應的ADC_INNx 連接到相應的信號線。
(5) OffsetNumber:使用偏移量的通道。當選擇第一個通道時,則第一個通道轉(zhuǎn)換的值需要減去一個偏移量,才能得到最終結果。
(6) Offset:偏移量。根據(jù)ADC 的分辨率不同,支持的最大偏移量也不同,例如分辨率是16bit,,最大的偏移量為0xFFFF。
(7) OffsetRightShift:采樣值進行右移的位數(shù)。
(8) OffsetSignedSaturation:是否使能ADC 采樣值的最高位為符號位。

因此對原驅(qū)動進行更改
(1)修改通道限制(位于stm32_get_adc_value函數(shù))
#if defined(SOC_SERIES_STM32F1)
    if (channel <= 17)
#elif defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32F2)  || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) \
        || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0)
    if (channel <= 18)
#elif defined(SOC_SERIES_STM32H7) //@dn 2020 1020
     if (channel <= 19)
#endif
    {
        /* set stm32 ADC channel */
        ADC_ChanConf.Channel = stm32_adc_get_channel(channel);
    }
    else
    {
#if defined(SOC_SERIES_STM32F1)
        LOG_E("ADC channel must be between 0 and 17.");
#elif defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32F2)  || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) \
        || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0)
        LOG_E("ADC channel must be between 0 and 18.");
#elif defined(SOC_SERIES_STM32H7) //@dn 2020 1020
        LOG_E("ADC channel must be between 0 and 19.");
#endif
        return -RT_ERROR;
    }
(2)修改轉(zhuǎn)換順序賦值(位于stm32_get_adc_value函數(shù))
原代碼:     
ADC_ChanConf.Rank = 1;
?
修改后:
ADC_ChanConf.Rank = ADC_REGULAR_RANK_1;//@dn 2020 1020
(3)加入H7支持,賦值采樣周期等
if defined(SOC_SERIES_STM32F0)
    ADC_ChanConf.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
#elif defined(SOC_SERIES_STM32F1)
    ADC_ChanConf.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
#elif defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7)
    ADC_ChanConf.SamplingTime = ADC_SAMPLETIME_112CYCLES;
#elif defined(SOC_SERIES_STM32L4)
    ADC_ChanConf.SamplingTime = ADC_SAMPLETIME_247CYCLES_5;
#elif defined(SOC_SERIES_STM32H7) //@dn 2020 1020
    ADC_ChanConf.SamplingTime = ADC_SAMPLETIME_810CYCLES_5;
#endif
#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32H7) //@dn 2020 1020
    ADC_ChanConf.Offset = 0;
#endif
#if defined (SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32H7) //@dn 2020 1020
    ADC_ChanConf.OffsetNumber = ADC_OFFSET_NONE;
    ADC_ChanConf.SingleDiff = ADC_SINGLE_ENDED;
#endif3.1 輪詢采集
       輪詢采集調(diào)用檢查EOC/EOS 置位的函數(shù) HAL_ADC_PollForConversion(),若進行多通道采集,則可多次調(diào)用該函數(shù)后讀取數(shù)據(jù)。
    HAL_ADC_Start(stm32_adc_handler);
    /* Wait for the ADC to convert */
    HAL_ADC_PollForConversion(stm32_adc_handler, 100);
    /* get ADC value */
    *value = (rt_uint32_t)HAL_ADC_GetValue(stm32_adc_handler);3.2 中斷采集
       使能ADC中斷后,轉(zhuǎn)換完成后調(diào)用HAL_ADC_ConvCpltCallback函數(shù),在函數(shù)中標志轉(zhuǎn)換完成,檢測轉(zhuǎn)換完成后讀取數(shù)據(jù)即可。若進行多通道采集,則可多次采集。
{
    if (stm32_adc_handler->Instance == ADC1)
    {
        HAL_NVIC_SetPriority(ADC_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(ADC_IRQn);
        irq_adc_num = 1;
    }
    else if (stm32_adc_handler->Instance == ADC2)
    {
        HAL_NVIC_SetPriority(ADC_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(ADC_IRQn);
        irq_adc_num = 2;
    }
    else
    {
        HAL_NVIC_SetPriority(ADC3_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(ADC3_IRQn);
    }
?
    HAL_ADC_Start_IT(stm32_adc_handler); //使能ADC中斷
    HAL_ADC_Start(stm32_adc_handler);    //軟件觸發(fā)ADC采樣
?
    for (rt_uint8_t i = 20; i <= 0; i--)
    {
        if (adc_convert_stat)
        {
            adc_convert_stat = 0;
            break;
        }
        else
        {
            if (i <= 1)
            {
                return RT_ERROR;
            }
            else
            {
                rt_thread_delay(5);
            }
        }
    }
    rt_thread_delay(5);
    *value = (rt_uint32_t)HAL_ADC_GetValue(stm32_adc_handler);
    HAL_ADC_Stop_IT(stm32_adc_handler);
}
?
void ADC_IRQHandler(void)
{
    rt_interrupt_enter();
?
    switch (irq_adc_num)
    {
#ifdef BSP_USING_ADC1
    case 1:
        HAL_ADC_IRQHandler(&stm32_adc_obj[ADC1_INDEX].ADC_Handler);
        break;
#endif
#ifdef BSP_USING_ADC2
    case 2:
        HAL_ADC_IRQHandler(&stm32_adc_obj[ADC2_INDEX].ADC_Handler);
        break;
#endif
    default:
        HAL_ADC_IRQHandler(&stm32_adc_obj[ADC1_INDEX].ADC_Handler);
        break;
    }
?
    rt_interrupt_leave();
}
void ADC3_IRQHandler(void)
{
    rt_interrupt_enter();
?
    HAL_ADC_IRQHandler(&stm32_adc_obj[ADC3_INDEX].ADC_Handler);
?
    rt_interrupt_leave();
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *AdcHandle)
{
    adc_convert_stat = 1;
}3.3 DMA采集
ADC DMA配置參數(shù),配置DMA通道等參數(shù)。
#define ADC1_DMA_CONFIG                                      \
    {                                                        \
        .Instance = DMA1_Stream1,                            \
        .Init.Request = DMA_REQUEST_ADC1,                    \
        .Init.Direction = DMA_PERIPH_TO_MEMORY,              \
        .Init.PeriphInc = DMA_PINC_DISABLE,                  \
        .Init.MemInc = DMA_MINC_ENABLE,                      \
        .Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD, \
        .Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD,    \
        .Init.Mode = DMA_CIRCULAR,                           \
        .Init.Priority = DMA_PRIORITY_LOW,                   \
        .Init.FIFOMode = DMA_FIFOMODE_DISABLE,               \
    }
      DMA初始化,需要注意的地方是:stm32_adc_obj[ i].ADC_Handler.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;[ i],ADC選用DMA的傳輸方式。
[ i]#ifdef ADC_USING_DMA
        __HAL_RCC_DMA1_CLK_ENABLE();
?
        if (HAL_DMA_Init(&adc_dma_config[ i]) != HAL_OK)
        {
            LOG_E("%s dma init failed", name_buf);
            result = -RT_ERROR;
        }
        LOG_D("%s dma init success.", name_buf);
?
        __HAL_LINKDMA(&stm32_adc_obj[ i].ADC_Handler, DMA_Handle, adc_dma_config[ i]);
?
        stm32_adc_obj[ i].ADC_Handler.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
#endif
使用DMA讀取數(shù)據(jù),下面的代碼為單通道的讀取方式,若使用多通道掃描讀取,可采用下面的方式多次采集,此外還可以通過定義數(shù)據(jù)存儲數(shù)組,打開ADC的ScanConvMode掃描選項、配置掃描通道數(shù)NbrOfConversion切對每個通道進行初始化,之后采集的多個數(shù)據(jù)將按照通道配置的采集順序存儲搭配定義的數(shù)組中。
__IO uint16_t ADC_ConvertedValue_DMA;
{
    HAL_ADC_Start_DMA(stm32_adc_handler, (uint32_t *)&ADC_ConvertedValue_DMA, 1);
?
    rt_thread_delay(1);
?
    SCB_InvalidateDCache_by_Addr((uint32_t *)&ADC_ConvertedValue_DMA, sizeof(ADC_ConvertedValue_DMA));
?
    *value = ADC_ConvertedValue_DMA;
}補充
由于作者的水平有限,本文可能存在一些描述不正確或存在錯誤的問題,若有錯誤,勞請告知,不勝感激。

評分

參與人數(shù) 1黑幣 +80 收起 理由
admin + 80 共享資料的黑幣獎勵!

查看全部評分

回復

使用道具 舉報

ID:251905 發(fā)表于 2022-2-10 09:10 | 顯示全部樓層
樓主你好,我H7驅(qū)動adc報錯,你有沒有遇到這個問題
1.png
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表