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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2538|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

STM32H7 ADC rtthread適配

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
筆記內(nèi)容
        針對RT-Thread官方源碼ADC驅(qū)動中沒有對STM32H7進(jìn)行支持,本文記錄了對原ADC驅(qū)動進(jìn)行修改以適配STM32H7的過程。
1.ADC驅(qū)動詳解
        外設(shè)驅(qū)動的使用邏輯都大體一致,先是外設(shè)初始化,大體包括時鐘初始化、I/O初始化、外設(shè)初始化,正確初始化后即可通過外設(shè)接口控制外設(shè)的工作,對于adc來說就是控制adc的采集,返回采集值。
        H7的adc可配置為 獨(dú)立/雙重 ,單/多通道,單次/連續(xù),單端/差分,輪詢/中斷/DMA 采集模式,可以配置的模式比較多,針對需求本文實(shí)現(xiàn)了 獨(dú)立 單通道 單純 單端的輪詢/中斷/DMA 采集模式。
2.ADC初始化
        RT-Thread使用自動初始化完成ADC的初始化設(shè)備注冊,初始化參數(shù)從 adc_config[] 中獲取。
ADC 初始化結(jié)構(gòu)體參數(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來說是不適用的,因此需進(jìn)行以下修改:
#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 標(biāo)志或者是EOS 標(biāo)志進(jìn)行轉(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:當(dāng)數(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中進(jìn)行ADC的使能和關(guān)閉操作,在實(shí)際測試過程中可不使用, stm32_adc_get_channel  完成ADC 通道配置、輪詢檢查轉(zhuǎn)換狀態(tài)、獲取轉(zhuǎn)換數(shù)據(jù)。
ADC_ChannelConfTypeDef 結(jié)構(gòu)體:
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)換通道。可以選擇0~19。
(2) Rank:ADC 轉(zhuǎn)換順序,可以選擇1~16。
(3) SamplingTime:ADC 的采樣周期。
(4) SingleDiff:選擇ADC 輸入信號的類型。可以選擇差分或者是單線。如果選擇差分模式,則需要將相應(yīng)的ADC_INNx 連接到相應(yīng)的信號線。
(5) OffsetNumber:使用偏移量的通道。當(dāng)選擇第一個通道時,則第一個通道轉(zhuǎn)換的值需要減去一個偏移量,才能得到最終結(jié)果。
(6) Offset:偏移量。根據(jù)ADC 的分辨率不同,支持的最大偏移量也不同,例如分辨率是16bit,,最大的偏移量為0xFFFF。
(7) OffsetRightShift:采樣值進(jìn)行右移的位數(shù)。
(8) OffsetSignedSaturation:是否使能ADC 采樣值的最高位為符號位。

因此對原驅(qū)動進(jìn)行更改
(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(),若進(jìn)行多通道采集,則可多次調(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ù)中標(biāo)志轉(zhuǎn)換完成,檢測轉(zhuǎn)換完成后讀取數(shù)據(jù)即可。若進(jìn)行多通道采集,則可多次采集。
{
    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掃描選項(xiàng)、配置掃描通道數(shù)NbrOfConversion切對每個通道進(jìn)行初始化,之后采集的多個數(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;
}補(bǔ)充
由于作者的水平有限,本文可能存在一些描述不正確或存在錯誤的問題,若有錯誤,勞請告知,不勝感激。

評分

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

查看全部評分

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

使用道具 舉報

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

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

1.png
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

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

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 午夜精品久久久 | 国产在线一区二区 | 999精品网| 第四色狠狠 | 黄网站免费在线看 | 国产欧美视频一区二区三区 | 中文字幕在线三区 | 免费av观看| 人人人人干 | 喷水毛片| 中文字幕第90页 | 欧美日本在线观看 | 久久亚洲春色中文字幕久久久 | 中文字幕av亚洲精品一部二部 | 中文字幕成人av | 成人精品 | 欧美成人一级视频 | 久久久久国产精品 | 日本中文字幕一区 | 狠狠操狠狠操 | 高清不卡毛片 | 日韩一区三区 | 男女午夜激情视频 | 欧美日韩国产一区 | 正在播放国产精品 | 国产一卡二卡三卡 | 午夜精品一区 | 一区二区三区免费在线观看 | 欧美久久综合 | 欧美综合一区二区三区 | 情侣酒店偷拍一区二区在线播放 | 在线一区视频 | 午夜精品久久久久久久久久久久 | 日韩欧美在线视频一区 | 午夜男人天堂 | 亚洲欧洲国产视频 | 亚洲精品乱码久久久久久9色 | 一区二区亚洲 | 国产精品成人一区二区三区夜夜夜 | 91不卡在线 | 欧美精品首页 |