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

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

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

使用STM32CubeMX生成初始化代碼

CHANBAEK ? 來(lái)源:頭條號(hào)科G棧 ? 作者:頭條號(hào)科G棧 ? 2023-03-22 15:26 ? 次閱讀

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

1、初始化

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

1、GPIO

這部分自動(dòng)生成就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的初始化自動(dòng)生成的程序會(huì)分為兩個(gè)部分:

第一個(gè)部分如下,會(huì)打開(kāi)時(shí)鐘、初始化中斷:

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);
//上面是自動(dòng)生成的,下面的部分需要自己添加
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);

自動(dòng)生成程序會(huì)完成DMA的如下設(shè)置:

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

我們需要自己添加:

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

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

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

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

3、I2C

I2C包括時(shí)鐘、中斷、地址、時(shí)鐘、模式等等

/* 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);
//上面的部分是自動(dòng)生成的,下面是自己添加的
    /* 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在通信過(guò)程中會(huì)產(chǎn)生很多中斷,比如地址匹配、NACK、STOP、錯(cuò)誤、溢出等等,這里根據(jù)需要只開(kāi)啟地址匹配中斷(ADDR),一旦檢測(cè)到地址匹配,我們就開(kāi)啟DMA傳輸數(shù)據(jù),其他的事情交給DMA處理。

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

到此初始化基本完成。

2、中斷處理程序

1、I2C中斷處理程序

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

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ù)方向開(kāi)啟對(duì)應(yīng)的DMA通道,清除ADDR標(biāo)志,之后數(shù)據(jù)就自動(dòng)通過(guò)DMA傳輸了。

2、DMA中斷處理程序

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

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

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

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

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

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

    關(guān)注

    28

    文章

    1477

    瀏覽量

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

    關(guān)注

    3

    文章

    556

    瀏覽量

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

    關(guān)注

    30

    文章

    4722

    瀏覽量

    68229
  • GPIO
    +關(guān)注

    關(guān)注

    16

    文章

    1188

    瀏覽量

    51832
  • stm32cubemx
    +關(guān)注

    關(guān)注

    5

    文章

    280

    瀏覽量

    14713
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    STM32CubeMx入門(mén)教程(3):定時(shí)器的使用

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

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

    導(dǎo)語(yǔ)“使用STM32CubeMx配置定時(shí)器輸出PWM波,生成初始化代碼?!?/div>
    發(fā)表于 07-11 15:23 ?2242次閱讀
    <b class='flag-5'>STM32CubeMx</b>入門(mén)教程(4):PWM應(yīng)用

    STM32接入PC后能枚舉出來(lái)麥克風(fēng)設(shè)備,但是開(kāi)始錄音后無(wú)數(shù)據(jù),為什么?

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

    STM32接入PC后能枚舉出來(lái)麥克風(fēng)設(shè)備,開(kāi)始錄音后無(wú)數(shù)據(jù)是怎么回事?

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

    【NUCLEO-F412ZG試用體驗(yàn)】一、USART+LED+KEY

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

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

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

    STM32CubeMX與HAL庫(kù)進(jìn)行開(kāi)發(fā)

    STM32CubeMX與HAL庫(kù)學(xué)習(xí)--基本定時(shí)器定時(shí)中斷背景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庫(kù)學(xué)習(xí)--TIM生成PWM的簡(jiǎn)單練習(xí)前言STM32CubeMX生成初始化
    發(fā)表于 01-12 07:21

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

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

    STM32F4 USB麥克風(fēng)錄音后無(wú)數(shù)據(jù),BUSHOUN數(shù)據(jù)長(zhǎng)度一直是0無(wú)法進(jìn)入函數(shù)USBD_AUDIO_DataIn怎么解決

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

    STM32CubeMX安裝與使用

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

    STM32CubeMX與HAL庫(kù)學(xué)習(xí)--ADC與USART的簡(jiǎn)單練習(xí)

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

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

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