RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

使用STM32CubeMX生成初始化代碼

CHANBAEK ? 來源:頭條號科G棧 ? 作者:頭條號科G棧 ? 2023-03-22 15:26 ? 次閱讀

我使用STM32CubeMX生成初始化代碼,使用LL庫,這里只介紹跟i2c相關(guān)的部分,其他必要的初始化需要自己完成。芯片使用stm32f042。本文的代碼不能到手即用,只提供思路。

1、初始化

初始化部分包括GPIO、DMA、I2C等。

1、GPIO

這部分自動生成就OK,一般不需要作修改;

LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
  /**I2C1 GPIO Configuration
  PA9   ------> I2C1_SCL
  PA10   ------> I2C1_SDA
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

2、DMA

DMA的初始化自動生成的程序會分為兩個部分:

第一個部分如下,會打開時鐘、初始化中斷:

void MX_DMA_Init(void)
{

  /* Init with LL driver */
  /* DMA controller clock enable */
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);

  /* DMA interrupt init */
    /* DMA1_Channel2_3_IRQn interrupt configuration */
  NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0);
  NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);

}

第二部分在I2C的初始化程序中

LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PRIORITY_HIGH);

LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MODE_NORMAL);

LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PERIPH_NOINCREMENT);

LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MEMORY_INCREMENT);

LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_BYTE);

LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_BYTE);
//上面是自動生成的,下面的部分需要自己添加
LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_3,5);
LL_DMA_SetMemoryAddress(DMA1,LL_DMA_CHANNEL_3,(uint32_t)i2cDataRx);
LL_DMA_SetPeriphAddress(DMA1,LL_DMA_CHANNEL_3,LL_I2C_DMA_GetRegAddr(I2C1,LL_I2C_DMA_REG_DATA_RECEIVE));  
LL_DMA_EnableIT_TC(DMA1,LL_DMA_CHANNEL_3);

自動生成程序會完成DMA的如下設(shè)置:

  • 數(shù)據(jù)傳輸方向
  • 通道極性
  • 模式
  • 外設(shè)地址模式
  • 內(nèi)存地址模式
  • 外設(shè)數(shù)據(jù)大小
  • 內(nèi)存數(shù)據(jù)大小

我們需要自己添加:

  • 傳輸數(shù)據(jù)個數(shù)
  • 設(shè)置內(nèi)存地址
  • 設(shè)置外設(shè)地址
  • 打開中斷,根據(jù)需要選擇傳輸完成、傳輸一半和傳輸錯誤

DMA的模式有兩種:NORMAL和CIRCULAR。

CIRCULAR模式一旦開始傳輸,DMA控制器就會自動不停的從源地址拿數(shù)據(jù)發(fā)送到目的地址,不需要我們干預。由于是異步的,如果內(nèi)存的數(shù)據(jù)多于1個,有可能出現(xiàn)內(nèi)存數(shù)據(jù)一部分新一部分舊的情況,導致數(shù)據(jù)不同步,如果各個數(shù)據(jù)之間獨立還好,如果是一個整體就會出問題,所以要根據(jù)實際需求決定是否使用這種方式。

NORMAL模式發(fā)送一次后就停止了,如果還要發(fā)送就需要我們先關(guān)閉DMA通道,設(shè)置傳輸?shù)臄?shù)據(jù)個數(shù),再打開通道,循環(huán)往復。本例使用這種方式,在中斷中處理三個過程,稍后介紹。

3、I2C

I2C包括時鐘、中斷、地址、時鐘、模式等等

/* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
  /* I2C1 interrupt Init */
  NVIC_SetPriority(I2C1_IRQn, 0);
  NVIC_EnableIRQ(I2C1_IRQn);
  /* USER CODE BEGIN I2C1_Init 1 */  
  /* USER CODE END I2C1_Init 1 */
  /** I2C Initialization
  */  
  LL_I2C_DisableGeneralCall(I2C1);
  LL_I2C_EnableClockStretching(I2C1);
  I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
  I2C_InitStruct.Timing = 0x2000090E;
  I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
  I2C_InitStruct.DigitalFilter = 0;
  I2C_InitStruct.OwnAddress1 = 0x5A;
  I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
  I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
  LL_I2C_Init(I2C1, &I2C_InitStruct);
  LL_I2C_EnableAutoEndMode(I2C1);
  LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
  LL_I2C_EnableOwnAddress2(I2C1);
//上面的部分是自動生成的,下面是自己添加的
    /* USER CODE BEGIN I2C1_Init 2 */
    LL_I2C_Enable(I2C1);
    LL_I2C_EnableIT_ADDR(I2C1);
   // LL_I2C_EnableIT_ERR(I2C1);
    LL_I2C_EnableDMAReq_RX(I2C1);
    LL_I2C_EnableDMAReq_TX(I2C1);

地址必須是偶數(shù),這里使用了雙地址,地址2是0,這樣0和5A都可以通信。

I2C在通信過程中會產(chǎn)生很多中斷,比如地址匹配、NACK、STOP、錯誤、溢出等等,這里根據(jù)需要只開啟地址匹配中斷(ADDR),一旦檢測到地址匹配,我們就開啟DMA傳輸數(shù)據(jù),其他的事情交給DMA處理。

最后兩個分別是啟用 DMA 接收請求和啟用 DMA 發(fā)送請求,只有開啟它們DMA和I2C才能關(guān)聯(lián)上。

到此初始化基本完成。

2、中斷處理程序

1、I2C中斷處理程序

這里就判斷是否地址匹配,如果匹配,判斷是讀還是寫,這里讀寫以主機視角確定,如果是WRITE,說明從機此時要接收數(shù)據(jù)。(這里我發(fā)現(xiàn)不同的版本和系列定義的還不一樣,使用的時候要注意。)

void I2C1_IRQHandler(void)
{
  /* USER CODE BEGIN I2C1_IRQn 0 */
    if(LL_I2C_IsActiveFlag_ADDR(I2C1))
    {
        if(LL_I2C_GetTransferDirection(I2C1) == LL_I2C_DIRECTION_WRITE)
        {
            LL_DMA_EnableChannel(DMA1,LL_DMA_CHANNEL_3);
        }
        else
        { 
            LL_DMA_EnableChannel(DMA1,LL_DMA_CHANNEL_2);  
        }
        /* Clear ADDR flag value in ISR register */
        LL_I2C_ClearFlag_ADDR(I2C1);
    }   
  /* USER CODE END I2C1_IRQn 0 */

  /* USER CODE BEGIN I2C1_IRQn 1 */

  /* USER CODE END I2C1_IRQn 1 */
}

這里根據(jù)方向開啟對應(yīng)的DMA通道,清除ADDR標志,之后數(shù)據(jù)就自動通過DMA傳輸了。

2、DMA中斷處理程序

這里由于通道2和3公用一個中斷,所以要先判斷是誰觸發(fā)的中斷,然后清除對應(yīng)的中斷標志。前面我們設(shè)置的是DMA傳輸完成中斷,所以進入這里就表面數(shù)據(jù)傳完了。由于我們使用的是NORMAL模式,所以我在這個回調(diào)里關(guān)閉通道并重設(shè)傳輸?shù)臄?shù)據(jù)個數(shù)。我之所以放到這里是考慮到傳輸玩數(shù)據(jù)后一般會有個間隔,這段時間沒事干就處理一下這些必要的事情,等下次想要傳輸?shù)臅r候直接打開就行。(前面在i2c中斷程序里我們可以看到打開通道的代碼。)你要是無所謂都放到I2C的中斷里也可以的。

void DMA1_Channel2_3_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel2_3_IRQn 0 */
    if(LL_DMA_IsActiveFlag_TC3(DMA1))
    {
        //LL_DMA_ClearFlag_GI3(DMA1);
        LL_DMA_ClearFlag_TC3(DMA1);
        
        I2C_SlaveDMARxCpltCallback();  
        LL_DMA_DisableChannel(DMA1,LL_DMA_CHANNEL_3);
        LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_3,5);      
    }
    else if (LL_DMA_IsActiveFlag_TC2(DMA1))
    {
        LL_DMA_ClearFlag_TC2(DMA1);
        LL_DMA_DisableChannel(DMA1,LL_DMA_CHANNEL_2);    
        LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_2,5);
    }
    
  /* USER CODE END DMA1_Channel2_3_IRQn 0 */

  /* USER CODE BEGIN DMA1_Channel2_3_IRQn 1 */

  /* USER CODE END DMA1_Channel2_3_IRQn 1 */
}

在接收中斷中有一個回調(diào)函數(shù)

I2C_SlaveDMARxCpltCallback(),里邊是用戶自定義程序,你想收到數(shù)據(jù)干啥就可以在這里邊處理。

剩下所要做的事情就是準備好要發(fā)送的數(shù)據(jù)和使用收到的數(shù)據(jù)就行了。

最近發(fā)現(xiàn)使用DMA真的很方便,尤其在發(fā)送或接收多個數(shù)據(jù)的時候,就不用for循環(huán)了,這樣既能收發(fā)大量數(shù)據(jù),還不會占用CPU時間,效率大大提高。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • I2C
    I2C
    +關(guān)注

    關(guān)注

    28

    文章

    1484

    瀏覽量

    123618
  • dma
    dma
    +關(guān)注

    關(guān)注

    3

    文章

    560

    瀏覽量

    100544
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4779

    瀏覽量

    68520
  • GPIO
    +關(guān)注

    關(guān)注

    16

    文章

    1204

    瀏覽量

    52051
  • stm32cubemx
    +關(guān)注

    關(guān)注

    5

    文章

    283

    瀏覽量

    14791
收藏 人收藏

    評論

    相關(guān)推薦

    STM32CubeMx入門教程(3):定時器的使用

    導語“ 使用STM32CubeMx 生成初始化定時器代碼,實現(xiàn)定時器特定定時”
    發(fā)表于 07-11 15:22 ?4038次閱讀
    <b class='flag-5'>STM32CubeMx</b>入門教程(3):定時器的使用

    STM32CubeMx入門教程(4):PWM應(yīng)用

    導語“使用STM32CubeMx配置定時器輸出PWM波,生成初始化代碼?!?/div> <b class='flag-5'>STM32CubeMx</b>入門教程(4):PWM應(yīng)用

    STM32接入PC后能枚舉出來麥克風設(shè)備,但是開始錄音后無數(shù)據(jù),為什么?

    采集MEMS數(shù)字麥克風PDM數(shù)據(jù),然后調(diào)用PDM2PCM庫轉(zhuǎn)換為PCM數(shù)據(jù),最后把PCM數(shù)據(jù)通過USB上傳給PC實現(xiàn)PC錄音使用的STM32CubeMx生成初始化代碼后默認是只有播放設(shè)
    發(fā)表于 03-18 08:25

    STM32接入PC后能枚舉出來麥克風設(shè)備,開始錄音后無數(shù)據(jù)是怎么回事?

    采集MEMS數(shù)字麥克風PDM數(shù)據(jù),然后調(diào)用PDM2PCM庫轉(zhuǎn)換為PCM數(shù)據(jù),最后把PCM數(shù)據(jù)通過USB上傳給PC實現(xiàn)PC錄音 使用的STM32CubeMx生成初始化代碼后默認是只有播放
    發(fā)表于 07-05 07:27

    【NUCLEO-F412ZG試用體驗】一、USART+LED+KEY

    USART+LED+KEY 開始。首先說明,使用 STM32CubeMx 生成初始化代碼工程,使用 HAL 庫編寫測試程序。1、打開 STM32C
    發(fā)表于 11-28 12:26

    【NUCLEO-F412ZG試用體驗】FreeRTOS創(chuàng)建任務(wù)

    。算了,還是改為 4 個 FreeRTOS測試吧。首先說明,本例程使用 STM32CubeMx 生成初始化代碼工程,使用 HAL庫編寫測試程序。實驗現(xiàn)象:1、3 個LED閃爍2、按下按
    發(fā)表于 12-13 21:00

    STM32CubeMX與HAL庫進行開發(fā)

    STM32CubeMX與HAL庫學習--基本定時器定時中斷背景STM32CubeMX生成初始化代碼在MDK-ARM里編輯
    發(fā)表于 08-11 06:59

    怎樣使用STM32CubeMx生成FMC的初始化代碼

    W9825G6KH-6的原理是怎樣的?怎樣使用STM32CubeMx生成FMC的初始化代碼呢?
    發(fā)表于 10-18 09:52

    如何利用STM32CubeMX生成STM32F429初始化代碼

    如何利用STM32CubeMX生成STM32F429初始化代碼呢?
    發(fā)表于 12-01 07:10

    TIM生成PWM的方法

    STM32CubeMX與HAL庫學習--TIM生成PWM的簡單練習前言STM32CubeMX生成初始化
    發(fā)表于 01-12 07:21

    STM32CubeMX外設(shè)在哪里初始化?

    。生成了 MX init 函數(shù),但在示例項目 STM32CubeMX 中配置為不生成函數(shù)調(diào)用。我找到了初始化ADC和GPIO引腳的地方,但是,我找不到
    發(fā)表于 01-11 06:28

    STM32F4 USB麥克風錄音后無數(shù)據(jù),BUSHOUN數(shù)據(jù)長度一直是0無法進入函數(shù)USBD_AUDIO_DataIn怎么解決

    采集MEMS數(shù)字麥克風PDM數(shù)據(jù),然后調(diào)用PDM2PCM庫轉(zhuǎn)換為PCM數(shù)據(jù),最后把PCM數(shù)據(jù)通過USB上傳給PC實現(xiàn)PC錄音 使用的STM32CubeMx生成初始化代碼后默認是只有播放
    發(fā)表于 08-07 08:16

    STM32CubeMX安裝與使用

    STM32CubeMX 是 ST 公司近幾年來大力推薦的STM32 芯片圖形配置工具,允許用戶使用圖形向?qū)?b class='flag-5'>生成C
    發(fā)表于 12-27 18:43 ?2次下載
    <b class='flag-5'>STM32CubeMX</b>安裝與使用

    STM32CubeMX與HAL庫學習--ADC與USART的簡單練習

    STM32CubeMX與HAL庫學習--ADC與USART的簡單練習前言STM32CubeMX生成初始化代碼在MDK-ARM里編輯
    發(fā)表于 01-12 20:27 ?13次下載
    <b class='flag-5'>STM32CubeMX</b>與HAL庫學習--ADC與USART的簡單練習

    STM32CubeMX用于STM32配置并初始化C代碼生成

    STM32CubeMX用于STM32配置 并初始化C代碼生成.STM32CubeMX
    發(fā)表于 02-14 11:00 ?5次下載
    RM新时代网站-首页