久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2817|回復: 1
打印 上一主題 下一主題
收起左側

STM32H7 ADC rtthread適配

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

因此對原驅動進行更改
(1)修改通道限制(位于stm32_get_adc_value函數)
#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)修改轉換順序賦值(位于stm32_get_adc_value函數)
原代碼:     
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 輪詢采集
       輪詢采集調用檢查EOC/EOS 置位的函數 HAL_ADC_PollForConversion(),若進行多通道采集,則可多次調用該函數后讀取數據。
    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中斷后,轉換完成后調用HAL_ADC_ConvCpltCallback函數,在函數中標志轉換完成,檢測轉換完成后讀取數據即可。若進行多通道采集,則可多次采集。
{
    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);    //軟件觸發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配置參數,配置DMA通道等參數。
#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讀取數據,下面的代碼為單通道的讀取方式,若使用多通道掃描讀取,可采用下面的方式多次采集,此外還可以通過定義數據存儲數組,打開ADC的ScanConvMode掃描選項、配置掃描通道數NbrOfConversion切對每個通道進行初始化,之后采集的多個數據將按照通道配置的采集順序存儲搭配定義的數組中。
__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;
}補充
由于作者的水平有限,本文可能存在一些描述不正確或存在錯誤的問題,若有錯誤,勞請告知,不勝感激。

評分

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

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:251905 發表于 2022-2-10 09:10 | 只看該作者
樓主你好,我H7驅動adc報錯,你有沒有遇到這個問題

1.png (20.46 KB, 下載次數: 87)

1.png
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 一区二区三区四区在线 | 久久96 | 成人高潮片免费网站 | 夜夜操天天操 | 亚洲激情一区二区 | 久久亚洲国产精品 | 国产在线一 | 中文字幕第一区 | 久久久久久综合 | 在线观看的av网站 | 99香蕉视频 | jlzzzjlzzz国产免费观看 | 国v精品久久久网 | 91亚洲国产成人久久精品麻豆 | 香蕉在线播放 | 国产精品一二三四 | 又黄又爽又刺激的视频 | 国产午夜三级一区二区三 | 精品国产伦一区二区三区 | 免费一区二区视频 | 三级av片| 日韩一级在线观看 | 国v精品久久久网 | 亚洲v视频 | 成人深夜福利视频 | 欧美性生交 | a级黄毛片| 99热免费| 色偷偷噜噜噜亚洲男人 | 午夜影院在线观看视频 | 国产一级片免费观看 | 午夜成人免费视频 | 毛片在线观看网站 | 最新日韩av | 国产一级18片视频 | 成年人免费在线视频 | 免费99精品国产自在在线 | av网站在线免费观看 | 国产第一福利 | 亚洲男人天堂网 | 欧美性生交xxxxx |