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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

STM32F407標準庫,SPI DMA中斷方式收發數據,怎么也調不通,一進DMA收發中斷程序就...

[復制鏈接]
回帖獎勵 100 黑幣 回復本帖可獲得 10 黑幣獎勵! 每人限 5 次
跳轉到指定樓層
樓主
ID:138119 發表于 2024-8-19 15:07 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
STM32F407標準庫,SPI DMA中斷方式收發數據,怎么也調不通,一進DMA收發中斷程序死了~(等待方式沒有問題),下面是代碼,請高手哥哥姐姐幫忙,謝謝!

//STM32F407標準庫,SPI DMA中斷方式收發數據,怎么也調不通,一進DMA收發中斷程序就...

#define SPI1_RX_LEN                        2000
#define SPI1_TX_LEN                        2000

#define SPI1_DR_ADDR        (uint32_t)0x4001300C

unsigned char SPI1_RX_BUFFER[SPI1_RX_LEN]={0};
unsigned char SPI1_TX_BUFFER[SPI1_TX_LEN]={0};

//函數名:初始化SPI接口
void SPI1_Init(void)
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        SPI_InitTypeDef  SPI_InitStructure;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);                                //使能SPI1時鐘
       
        GPIO_InitStructure.GPIO_Pin = SPI1_NSS_Pin;                                                        //IO
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                                                //標準功能
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                                                //推挽輸出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;                                        //100MHz
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                                                //上拉
        GPIO_Init(SPI1_NSS_GPIO_Port, &GPIO_InitStructure);                                        //初始化
        SPI1_NSS_Set();        //NSS高
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;                        //PA5\6\7復用功能輸出       
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                                                        //復用功能
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                                                        //推挽輸出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;                                                //100MHz
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                                                        //上拉
        GPIO_Init(GPIOA, &GPIO_InitStructure);                                                                        //初始化
       
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_SPI1);                                        //PB3復用為 SPI1
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_SPI1);                                        //PB4復用為 SPI1
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_SPI1);                                        //PB5復用為 SPI1
        //只針對SPI口初始化
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);                                                //復位SPI1
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);                                        //停止復位SPI1
       
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;                //設置SPI單向或者雙向的數據模式:SPI設置為雙線雙向全雙工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                                                        //設置SPI工作模式:設置為主SPI
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                                                //設置SPI的數據大小:SPI發送接收8位幀結構
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                                                                //串行同步時鐘的空閑狀態為高電平
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                                                        //串行同步時鐘的第二個跳變沿(上升或下降)數據被采樣
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                                                //NSS信號由硬件(NSS管腳)還是軟件(使用SSI位)管理:內部NSS信號有SSI位控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;                //定義波特率預分頻的值:波特率預分頻值為2:42M;4:21M;8:10.5M;16:5.25M
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                                                //指定數據傳輸從MSB位還是LSB位開始:數據傳輸從MSB位開始
        SPI_InitStructure.SPI_CRCPolynomial = 7;                                                                //CRC值計算的多項式
        SPI_Init(SPI1, &SPI_InitStructure);                                                                          //根據SPI_InitStruct中指定的參數初始化外設SPIx寄存器

        SPI_Cmd(SPI1, ENABLE);                                //使能SPI外設
        spi1_dma_init(41,41);                                //DMA初始化
        SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
        SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
}

void spi1_dma_init(unsigned short RXSize,unsigned short TXSize)
{
        DMA_InitTypeDef DMA_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        /*DMA2*/
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
        /* DMA RX config */
        DMA_InitStructure.DMA_Channel = DMA_Channel_3;                                                        //DMA  通道
        DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_ADDR;                                 //外設地址
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SPI1_RX_BUFFER;                //接收緩沖區(內存中的有一個數組)
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                                        //DMA 傳輸方向
        DMA_InitStructure.DMA_BufferSize = RXSize;                                                                //DMA 傳輸的數量        這個后期還可以再改
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                //外設地址自增  取消
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                        //內存地址自增  使能
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                        //傳輸的 單位 (byte  8bit)
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;        //傳輸的 單位 (byte  8bit)
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                                        //普通模式  傳輸完成一次就自動結束
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                                        //優先級 中等
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                                        //不使用 FIFO
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;                        //
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                                //
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
        DMA_Init(DMA2_Stream2, &DMA_InitStructure);                                                                //初始化
        /* DMA TX Config */
        DMA_InitStructure.DMA_Channel = DMA_Channel_3;                                                        //DMA  通道
        DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_ADDR;                                //外設地址
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SPI1_TX_BUFFER;                //接收緩沖區(內存中的有一個數組)
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                                        //DMA傳輸方向
        DMA_InitStructure.DMA_BufferSize = TXSize;                                                                //DMA傳輸的數量        這個后期還可以再改
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                //外設地址自增  取消
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                        //內存地址自增  使能
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                        //傳輸的 單位 (byte  8bit)
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;        //傳輸的 單位 (byte  8bit)
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                                        //普通模式  傳輸完成一次就自動結束
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                                        //優先級 中等
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
        DMA_Init(DMA2_Stream3, &DMA_InitStructure);                                                                //初始化
       
        //DMA中斷方式發送
        DMA_ITConfig(DMA2_Stream3, DMA_IT_TC, ENABLE);                                                        //DMA發送中斷開
        NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        DMA_ClearITPendingBit(DMA2_Stream3, DMA_IT_TCIF3);
       
        //DMA中斷方式接收       
        DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);                                                        //DMA接收中斷開
        NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);
}

//讀寫數據調用此函數
void spi1_trans(unsigned char *rx_buf, unsigned char *tx_buf, unsigned short length)       
{
        DMA_Cmd(DMA2_Stream2, DISABLE);                                                                                //關閉DMA
        DMA_Cmd(DMA2_Stream3, DISABLE);                                                                                //關閉DMA
       
        DMA_SetCurrDataCounter(DMA2_Stream2, (unsigned short)length);                //設置DMA的傳輸參數
        DMA_SetCurrDataCounter(DMA2_Stream3, (unsigned short)length);                //設置DMA的傳輸參數

        DMA2_Stream2->M0AR = (uint32_t)rx_buf;                                                                //設置內存的起始地址
        DMA2_Stream3->M0AR = (uint32_t)tx_buf;                                                                //設置內存的起始地址
       
        SPI1->DR;
        //while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);        //等待先前的發送完畢

        DMA_Cmd(DMA2_Stream2, ENABLE);                                                                                //打開DMA開始發送
        DMA_Cmd(DMA2_Stream3, ENABLE);                                                                                //打開DMA開始接收

        //while( DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_TCIF3) == RESET);  //等待數據發送完
        //while( DMA_GetFlagStatus(DMA2_Stream2, DMA_FLAG_TCIF2) == RESET);  //等待
        //DMA_Cmd(DMA2_Stream2, DISABLE);                                                                        //發送完關閉DMA
        //DMA_Cmd(DMA2_Stream3, DISABLE);                                                                        //發送完關閉DMA
        //DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2);                                                //清楚標志位
        //DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_TCIF3);                                                //清楚標志位
}

//發送中斷
void DMA2_Stream2_IRQHandler(void)  
{
        // 清除DMA發送完成標志
        if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TCIF2)!= RESET)
    {
                // 清除DMA發送完成標志
                DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);
                DMA_Cmd(DMA2_Stream2, DISABLE);
                u1_printf("S2_TX_IRQ\r\n");
    }
        // 傳輸錯誤中斷
        if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TEIF2) != RESET)
        {
                 DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TEIF2);
                u1_printf("S2_err_TEIF2\r\n");
        }
}       

//接收中斷
void DMA2_Stream3_IRQHandler(void)
{
        // 清除DMA發送完成標志
        if(DMA_GetITStatus(DMA2_Stream3, DMA_IT_TCIF3)!= RESET)
    {
                DMA_ClearITPendingBit(DMA2_Stream3, DMA_IT_TCIF3);
                DMA_Cmd(DMA2_Stream3, DISABLE);
                u1_printf("S3_RX_IRQ\r\n");
    }
       
        // 傳輸錯誤中斷
        if(DMA_GetITStatus(DMA2_Stream3, DMA_IT_TEIF3) != RESET)
        {
                 DMA_ClearITPendingBit(DMA2_Stream3, DMA_IT_TEIF3);
                        u1_printf("S3_err_TEIF3\r\n");
        }
}


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

使用道具 舉報

沙發
ID:404160 發表于 2024-8-27 12:12 | 只看該作者
DMA中斷使能:您在spi1_dma_init函數中使能了DMA中斷,但在spi1_trans函數中似乎沒有適當的方式去等待DMA中斷發生。while循環被注釋掉了,如果DMA中斷沒有正確觸發,程序就不會繼續執行。

DMA傳輸方向設置:在spi1_dma_init函數中,RX和TX的DMA配置都使用了相同的DMA通道3,這可能會導致問題。通常,接收和發送應該使用不同的DMA通道,以便它們可以同時進行。

中斷服務函數:在DMA中斷服務函數DMA2_Stream2_IRQHandler和DMA2_Stream3_IRQHandler中,您只處理了傳輸完成中斷(TCIF),但是沒有處理半傳輸完成中斷(HTIF),這可能影響DMA的效率和性能。

SPI傳輸開始:在spi1_trans函數中,您直接啟動了DMA,但是沒有通過SPI的發送函數開始傳輸。這可能導致DMA嘗試從SPI讀取/寫入數據,但是SPI并未開始傳輸。

代碼注釋和邏輯:部分代碼被注釋掉,比如等待DMA傳輸完成的循環。這些代碼如果取消注釋,可能會幫助程序正常工作

針對您的代碼,以下是一些具體的檢查點:

確保DMA2_Stream2_IRQHandler和DMA2_Stream3_IRQHandler中斷服務函數中沒有無限循環。
檢查中斷優先級設置是否合理,沒有其他中斷被錯誤地屏蔽。
確保ISR中沒有調用阻塞函數或執行耗時操作。
確保DMA中斷標志位在ISR中被正確清除。
檢查是否有可能在ISR中訪問了被其他任務使用的共享資源。
回復

使用道具 舉報

板凳
ID:276685 發表于 2024-8-27 18:25 | 只看該作者
建議debug一下看程序死在哪,檢查一下void XXXX_IRQHandler(void)這個函數在.h文件定義了沒有,如果沒有系統會在中斷來臨時進入空函數循環
回復

使用道具 舉報

地板
ID:982617 發表于 2024-8-29 09:34 | 只看該作者
你的代碼中可能存在以下幾個問題,導致程序進入中斷后卡死:  1. **DMA通道配置沖突:** 你在 `spi1_dma_init` 函數中,對 DMA2 的 Stream2 和 Stream3 都使用了 `DMA_Channel_3`。  STM32F407 的 DMA2 控制器中,Stream2 和 Stream3 共享一個通道(Channel 3)。 你需要根據 SPI1 的實際 DMA 請求映射選擇正確的 Stream 和 Channel 組合。 請參考 STM32F407 數據手冊中 "DMA requests mapping" 章節查找 SPI1_TX 和 SPI1_RX 對應的 DMA 請求。  2. **中斷處理函數中的 `printf`:**  在中斷處理函數 `DMA2_Stream2_IRQHandler` 和 `DMA2_Stream3_IRQHandler` 中使用了 `u1_printf` 函數。 在中斷處理函數中使用 `printf` 等重量級函數可能會導致程序卡死,尤其是在中斷頻繁觸發的情況下。 盡量簡化中斷處理函數的邏輯,例如僅設置標志位或執行一些簡單的操作,將耗時的操作放到主循環中處理。  3. **DMA 緩沖區大小:** 你的 `SPI1_RX_BUFFER` 和 `SPI1_TX_BUFFER` 數組大小為 2000 字節,請確保你的 MCU 有足夠的 RAM 空間來容納這兩個數組。  4. **DMA 傳輸模式:** 你使用了 `DMA_Mode_Normal` 模式,這意味著每次 DMA 傳輸完成后都需要重新配置 DMA 控制器。 如果你的應用需要連續傳輸數據,可以考慮使用 `DMA_Mode_Circular` 循環模式,避免頻繁配置 DMA 控制器。  5. **SPI 配置:** 請確保 SPI1 的波特率、時鐘極性、時鐘相位等配置與你的 SPI 從設備一致。   **建議修改:**  1. **確認 DMA 通道映射:**  仔細閱讀 STM32F407 數據手冊,確定 SPI1_TX 和 SPI1_RX 對應的 DMA 請求和通道。 修改 `spi1_dma_init` 函數,使用正確的 Stream 和 Channel 初始化 DMA。  2. **簡化中斷處理:** 將 `u1_printf` 從中斷處理函數中移除,可以使用全局變量或標志位來指示 DMA 傳輸完成或出現錯誤。  3. **檢查內存分配:** 確保你的 MCU 有足夠的 RAM 空間來存儲 DMA 緩沖區。  4. **嘗試循環模式:** 如果需要連續傳輸數據,修改 DMA 模式為 `DMA_Mode_Circular`。  5. **仔細檢查 SPI 配置:**  確保 SPI1 的配置參數與你的 SPI 從設備匹配。   **調試建議:**  1. 使用調試器單步執行程序,觀察程序卡死的位置。  2. 在中斷處理函數中設置斷點,查看中斷是否被正確觸發。  3. 使用邏輯分析儀抓取 SPI 總線上的信號,分析 SPI 通信是否正常。     通過以上步驟排查問題,你應該能夠解決 SPI DMA 中斷方式數據傳輸的問題。
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 视频在线日韩 | 成人在线观看中文字幕 | 久久精品一区 | 日本免费在线 | 在线视频一区二区 | 在线免费看毛片 | 超碰精品在线 | 成人日韩 | 美女视频一区二区三区 | 欧美黄视频 | 国产91久久久久久久免费 | 国产成人一区在线 | www.一区二区三区 | 99久久99| 欧美理论片在线 | 亚洲一区二区视频 | 免费观看一级特黄欧美大片 | 欧美一区二区综合 | 日韩爱爱网| 成人精品国产免费网站 | 欧美videosex性极品hd | 国产精品久久久久久久久久久新郎 | 日韩在线精品视频 | 亚洲免费精品一区 | 天天草天天操 | 精品日韩一区二区 | 久久久蜜桃一区二区人 | 亚洲成人三级 | 国产精品久久久久久久久免费丝袜 | 91文字幕巨乱亚洲香蕉 | 国产乱一区二区三区视频 | 精品国产一区二区在线 | 亚洲午夜精品在线观看 | 国产午夜久久久 | 久久久123 | 国产资源在线视频 | 一区二区国产精品 | 精品国产一区二区三区性色av | 天天澡天天操 | 成人av网站在线观看 | www.天堂av.com |