专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
STM32
在STM32H7 MCU上配置DMA请求多路复用器
2019-07-14 17:58
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
STM32/STM8
14425
6
961
我最近使用新生产的SM32H7 MCU,目前正在将一些旧代码迁移到它们(我想看看他们如何处理一些需要更高速度的应用程序)。H7具有DMA请求多路复用器,在我曾经使用的旧F7,F4或F3中不存在。在后一种模型中,通过向DMA_x Stream_y控制寄存器输入正确的值来完成DMA通道映射。例如
DMA2_Stream3->CR |= (0x3 << DMA_SxCR_CHSEL_Pos);
将为DM2 Stream3选择第三个通道(在F7 MCU的情况下,这将对应于SPI1 TX DMA请求:
据我所知,DMA流到DMA通道映射不再是“硬连线”,它可以在H7系列中手动重新配置。正如手册所述,必须使用DMAMux1将DMA请求线路连接到DMA通道。不幸的是,DMAMUX配置在参考手册中描述得相当差。我还没有意识到如何准确DMA流,外设和DMA通道通过多路复用器互连。下面是一段代码,理想情况下应该是
设置SPI1。
设置DMA。
启用DMA流以进行SPI TX传输
<font size="4">RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN; // Enable usage of GPIOA
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
GPIOA->MODER &= ~GPIO_MODER_MODER5;
GPIOA->MODER |= GPIO_MODER_MODER5_1; // Alternate func
ti
on for SPI1 SCK on PA5
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5; // High Speed on PA5
GPIOA->AFR[0] |= (0x05 << 5 * 4); // AFRL selected AF5 (SPI1 SCK) for PA5
GPIOA->MODER &= ~GPIO_MODER_MODER6;
GPIOA->MODER |= GPIO_MODER_MODER6_1; // Alternate function for SPI1 MISO on PA6
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6; // High Speed on PA6
GPIOA->AFR[0] |= (0x05 << 6 * 4); // AFRL selected AF5 (SPI1 MISO) for PA6
GPIOA->MODER &= ~GPIO_MODER_MODER7;
GPIOA->MODER |= GPIO_MODER_MODER7_1; // Alternate function for SPI1 MOSI on PA7
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7; // High Speed on PA7
GPIOA->AFR[0] |= (0x05 << 7 * 4); // AFRL selected AF5 (SPI1 MOSI) for PA7
GPIOA->MODER &= ~GPIO_MODER_MODER4;
GPIOA->MODER |= GPIO_MODER_MODER4_1; // Alternate function for SPI1 NSS on PA7
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR4; // High Speed on PA7
GPIOA->AFR[0] |= (0x05 << 4 * 4); // AFRL selected AF5 (SPI1 NSS) for PA7
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR4_0; // Ensure all pull up pull down resistors are enabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5; // Ensure all pull up pull down resistors are disabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR6; // Ensure all pull up pull down resistors are disabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR7; // Ensure all pull up pull down resistors are disabled
SPI1->CFG1 = (1u << SPI_CFG1_MBR_Pos) | // Master baud rate: master clock / 2
(7u << SPI_CFG1_CRCSIZE_Pos) | // Length of CRC frame
SPI_CFG1_TXDMAEN | SPI_CFG1_RXDMAEN | // Enable RX/TX DMA
(7u << SPI_CFG1_FTHLV_Pos) | // FIFO threshold level
(7u << SPI_CFG1_DSIZE_Pos) //Number of bits in at single SPI data frame
;
SPI1->CFG2 = SPI_CFG2_SSOE | // SS output enable
SPI_CFG2_MASTER // SPI Master
;
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; // DMA2 clock enable;
DMA2_Stream3->CR = 0u;
DMA2_Stream3->PAR = (uint32_t) &(SPI1->TXDR);
DMA2_Stream3->M0AR = (uint32_t) &(Data_Buffer[0]);
DMA2_Stream3->CR |= (1u << DMA_SxCR_DIR_Pos);
DMA2_Stream3->CR |= DMA_SxCR_MINC;
DMA2_Stream3->CR |= DMA_SxCR_PL;
DMA2_Stream3->NDTR = 1000;
// 5. Use DMAMux1 to route a DMA request line to the DMA channel.
DMAMUX1_Channel0->CCR = (37u << DMAMUX_CxCR_DMAREQ_ID_Pos);
SPI1->CR1 |= SPI_CR1_SPE;
DMA2_Stream3->CR |= DMA_SxCR_EN;</font>
复制代码
此代码编译,我可以将其上传到
STM32
H753ZIT6 MCU。完整的代码还有PLL设置,它不包含在上面的代码段中(PLL初始化工作得很好,因为我能够探测MCO引脚上的400 MHz系统时钟)。
DMA多路复用器设置无疑是不完整的。我只选择了一个适当的多路复用器输入资源。我甚至不确定多路复用器通道是否正确(或者他们的选择在H7 MCU中是否是任意的)。
所以我的问题是为SPI TX传输设置DMA多路复用器的正确方法是什么?如果我可以运行这个MWE,我或多或少能够完成我的其余代码的迁移。
所以,我一直在尝试关注user9403409的建议,但不幸的是,我无法走得太远。我仍然无法让SPI在H7系列微控制器上通过DMA工作。现在我可以让SPI在没有H7的DMA的情况下正常工作:
<font size="4">#include "stm32h7xx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void InitializeMCO(void);
static void ConfigureHSI(void);
static void InitializeMasterTxSPI(void);
uint8_t s_TransferBuffer[10];
int main()
{
s_TransferBuffer[0] = 0xAA;
s_TransferBuffer[1] = 0xBB;
s_TransferBuffer[2] = 0xCC;
ConfigureHSI();
InitializeMCO();
InitializeMasterTxSPI();
while(1){};
}
static void ConfigureHSI(void)
{
PWR->CR3 |= PWR_CR3_SCUEN;
PWR->D3CR |= (PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0);
while ((PWR->D3CR & PWR_D3CR_VOSRDY) != PWR_D3CR_VOSRDY)
{
};
FLASH->ACR = FLASH_ACR_LATENCY_2WS;
RCC->CR |= RCC_CR_HSION;
while ((RCC->CR & RCC_CR_HSIRDY) != RCC_CR_HSIRDY)
{
};
RCC->PLLCKSELR = (4u << RCC_PLLCKSELR_DIVM1_Pos) |
(32u << RCC_PLLCKSELR_DIVM2_Pos) |
(32u << RCC_PLLCKSELR_DIVM3_Pos) |
RCC_PLLCKSELR_PLLSRC_HSI
;
RCC->PLLCFGR = RCC_PLLCFGR_DIVR1EN |
RCC_PLLCFGR_DIVQ1EN |
RCC_PLLCFGR_DIVP1EN |
(2u << RCC_PLLCFGR_PLL1RGE_Pos) |
(1u << RCC_PLLCFGR_PLL1VCOSEL_Pos)
;
RCC->PLL1DIVR = ((2u - 1u) << RCC_PLL1DIVR_R1_Pos) |
((2u - 1u) << RCC_PLL1DIVR_Q1_Pos) |
((2u - 1u) << RCC_PLL1DIVR_P1_Pos) |
((10u - 1u) << RCC_PLL1DIVR_N1_Pos) // Reducing the clock rate so I can probe it with my slow USB scope
;
RCC->D1CFGR = RCC_D1CFGR_D1CPRE_DIV1;
RCC->D1CFGR = RCC_D1CFGR_HPRE_DIV2 |
RCC_D1CFGR_D1PPRE_DIV2;
RCC->D2CFGR = RCC_D2CFGR_D2PPRE1_DIV2 |
RCC_D2CFGR_D2PPRE2_DIV2;
RCC->D3CFGR = RCC_D3CFGR_D3PPRE_DIV2;
RCC->CR |= RCC_CR_PLL1ON;
while (!(RCC->CR & RCC_CR_PLLRDY))
{
};
RCC->CFGR |= (1u << 25);
RCC->CFGR |= RCC_CFGR_SW_PLL1;
while (!(RCC->CFGR & RCC_CFGR_SWS_PLL1))
{
};
}
/* Displays MCO on PC9 */
static void InitializeMCO(void)
{
RCC->CFGR |= RCC_CFGR_MCO2;
RCC->CFGR |= (15 << 25); // Reducing the output so I can probe it with my slow USB scope
RCC->AHB4ENR &= ~RCC_AHB4ENR_GPIOCEN;
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOCEN;
GPIOC->MODER &= ~GPIO_MODER_MODER9;
GPIOC->MODER |= GPIO_MODER_MODER9_1;
GPIOC->OTYPER &= ~GPIO_OTYPER_OT_9;
GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR9;
GPIOC->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR9;
GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;
GPIOC->AFR[0] &= ~GPIO_AFRL_AFRL0;
}
static void InitializeMasterTxSPI(void)
{
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN; // Enable usage of GPIOA
GPIOA->MODER &= ~GPIO_MODER_MODER5;
GPIOA->MODER |= GPIO_MODER_MODER5_1; // Alternate function for SPI1 SCK on PA5
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5; // High Speed on PA5
GPIOA->AFR[0] |= (0x05 << 5 * 4); // AFRL selected AF5 (SPI1 SCK) for PA5
GPIOA->MODER &= ~GPIO_MODER_MODER6;
GPIOA->MODER |= GPIO_MODER_MODER6_1; // Alternate function for SPI1 MISO on PA6
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6; // High Speed on PA6
GPIOA->AFR[0] |= (0x05 << 6 * 4); // AFRL selected AF5 (SPI1 MISO) for PA6
GPIOA->MODER &= ~GPIO_MODER_MODER7;
GPIOA->MODER |= GPIO_MODER_MODER7_1; // Alternate function for SPI1 MOSI on PA7
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7; // High Speed on PA7
GPIOA->AFR[0] |= (0x05 << 7 * 4); // AFRL selected AF5 (SPI1 MOSI) for PA7
GPIOA->MODER &= ~GPIO_MODER_MODER4;
GPIOA->MODER |= GPIO_MODER_MODER4_1; // Alternate function for SPI1 NSS on PA7
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR4; // High Speed on PA7
GPIOA->AFR[0] |= (0x05 << 4 * 4); // AFRL selected AF5 (SPI1 NSS) for PA7
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR4; // Ensure all pull up pull down resistors are enabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5; // Ensure all pull up pull down resistors are disabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR6; // Ensure all pull up pull down resistors are disabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR7; // Ensure all pull up pull down resistors are disabled
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
SPI1->CR1 = 0;
SPI1->CFG1 = (3u << SPI_CFG1_MBR_Pos) |
(7u << SPI_CFG1_CRCSIZE_Pos) |
//SPI_CFG1_TXDMAEN | // SPI_CFG1_RXDMAEN |
(7u << SPI_CFG1_FTHLV_Pos) |
(7u << SPI_CFG1_DSIZE_Pos)
;
SPI1->CFG2 = SPI_CFG2_SSOE |
SPI_CFG2_MASTER
;
SPI1->CR2 |= 3;
SPI1->CR1 |= SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_CSTART;
for (uint32_t i=0; i<3; i++)
{
while ((SPI1->SR & SPI_SR_TXP) != SPI_SR_TXP){};
*((__IO uint32_t *)&SPI1->TXDR) = *((uint32_t *)&s_TransferBuffer[i]);
}
}</font>
复制代码
上面的代码基本上做了三件事:
ConfigureHSI 初始化HSI时钟(我已经降低了时钟速度,以便能够使用我目前拥有的慢速USB示波器进行一些探测)。
InitializeMCO 显示主时钟输出(只是为了确保时钟配置正确)。
InitializeMasterTxSPI 配置SPI并发出三字节消息。
我绝对可以看到在我的示波器上发送的消息:
时基为200 ns / div,供参考。
另一方面,如果我尝试通过DMA重做整个事情,我看不到任何输出。这就是我的基于DMA的SPI代码:
<font size="4">#include "stm32h7xx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void InitializeMCO(void);
static void ConfigureHSI(void);
static void InitializeDMA(void);
static void InitializeMasterTxSPI(void);
uint8_t s_TransferBuffer[10];
int main()
{
s_TransferBuffer[0] = 0xAA;
s_TransferBuffer[1] = 0xBB;
s_TransferBuffer[2] = 0xCC;
ConfigureHSI();
InitializeMCO();
InitializeDMA();
InitializeMasterTxSPI();
while(1){};
}
/* Initializes the MCU clock */
static void ConfigureHSI(void)
{
PWR->CR3 |= PWR_CR3_SCUEN;
PWR->D3CR |= (PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0);
while ((PWR->D3CR & PWR_D3CR_VOSRDY) != PWR_D3CR_VOSRDY)
{
};
FLASH->ACR = FLASH_ACR_LATENCY_2WS;
RCC->CR |= RCC_CR_HSION;
while ((RCC->CR & RCC_CR_HSIRDY) != RCC_CR_HSIRDY)
{
};
RCC->PLLCKSELR = (4u << RCC_PLLCKSELR_DIVM1_Pos) |
(32u << RCC_PLLCKSELR_DIVM2_Pos) |
(32u << RCC_PLLCKSELR_DIVM3_Pos) |
RCC_PLLCKSELR_PLLSRC_HSI
;
RCC->PLLCFGR = RCC_PLLCFGR_DIVR1EN |
RCC_PLLCFGR_DIVQ1EN |
RCC_PLLCFGR_DIVP1EN |
(2u << RCC_PLLCFGR_PLL1RGE_Pos) |
(1u << RCC_PLLCFGR_PLL1VCOSEL_Pos)
;
RCC->PLL1DIVR = ((2u - 1u) << RCC_PLL1DIVR_R1_Pos) |
((2u - 1u) << RCC_PLL1DIVR_Q1_Pos) |
((2u - 1u) << RCC_PLL1DIVR_P1_Pos) |
((10u - 1u) << RCC_PLL1DIVR_N1_Pos) // Reducing the clock rate so I can probe it with my slow USB scope
;
RCC->D1CFGR = RCC_D1CFGR_D1CPRE_DIV1;
RCC->D1CFGR = RCC_D1CFGR_HPRE_DIV2 |
RCC_D1CFGR_D1PPRE_DIV2;
RCC->D2CFGR = RCC_D2CFGR_D2PPRE1_DIV2 |
RCC_D2CFGR_D2PPRE2_DIV2;
RCC->D3CFGR = RCC_D3CFGR_D3PPRE_DIV2;
RCC->CR |= RCC_CR_PLL1ON;
while (!(RCC->CR & RCC_CR_PLLRDY))
{
};
RCC->CFGR |= (1u << 25);
RCC->CFGR |= RCC_CFGR_SW_PLL1;
while (!(RCC->CFGR & RCC_CFGR_SWS_PLL1))
{
};
}
/* Displays MCO on PC9 */
static void InitializeMCO(void)
{
RCC->CFGR |= RCC_CFGR_MCO2;
RCC->CFGR |= (15 << 25); // Reducing the output so I can probe it with my slow USB scope
RCC->AHB4ENR &= ~RCC_AHB4ENR_GPIOCEN;
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOCEN;
GPIOC->MODER &= ~GPIO_MODER_MODER9;
GPIOC->MODER |= GPIO_MODER_MODER9_1;
GPIOC->OTYPER &= ~GPIO_OTYPER_OT_9;
GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR9;
GPIOC->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR9;
GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;
GPIOC->AFR[0] &= ~GPIO_AFRL_AFRL0;
}
static void InitializeDMA()
{
RCC->AHB2ENR |= (0x7 << 29); // Enable the SRAM
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; // DMA1 clock enable;
// Set the peripheral and memory addresses:
DMA1_Stream0->PAR = *((__IO uint32_t *)&SPI1->TXDR);
DMA1_Stream0->M0AR = *((uint32_t *)&s_TransferBuffer[0]);
DMA1_Stream0->CR = 0u;
DMA1_Stream0->CR |= (1u << DMA_SxCR_DIR_Pos); // Memory to peripheral
DMA1_Stream0->CR |= DMA_SxCR_MINC; // Memory increment mode
DMA1_Stream0->CR |= (3u << DMA_SxCR_PL_Pos); // Very high priority
DMA1_Stream0->NDTR = 3; // Number of data
DMAMUX1_Channel0->CCR = (38u << DMAMUX_CxCR_DMAREQ_ID_Pos);
}
static void InitializeMasterTxSPI(void)
{
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN; // Enable usage of GPIOA
GPIOA->MODER &= ~GPIO_MODER_MODER5;
GPIOA->MODER |= GPIO_MODER_MODER5_1; // Alternate function for SPI1 SCK on PA5
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5; // High Speed on PA5
GPIOA->AFR[0] |= (0x05 << 5 * 4); // AFRL selected AF5 (SPI1 SCK) for PA5
GPIOA->MODER &= ~GPIO_MODER_MODER6;
GPIOA->MODER |= GPIO_MODER_MODER6_1; // Alternate function for SPI1 MISO on PA6
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6; // High Speed on PA6
GPIOA->AFR[0] |= (0x05 << 6 * 4); // AFRL selected AF5 (SPI1 MISO) for PA6
GPIOA->MODER &= ~GPIO_MODER_MODER7;
GPIOA->MODER |= GPIO_MODER_MODER7_1; // Alternate function for SPI1 MOSI on PA7
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7; // High Speed on PA7
GPIOA->AFR[0] |= (0x05 << 7 * 4); // AFRL selected AF5 (SPI1 MOSI) for PA7
GPIOA->MODER &= ~GPIO_MODER_MODER4;
GPIOA->MODER |= GPIO_MODER_MODER4_1; // Alternate function for SPI1 NSS on PA4
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR4; // High Speed on PA4
GPIOA->AFR[0] |= (0x05 << 4 * 4); // AFRL selected AF5 (SPI1 NSS) for PA4
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR4; // Ensure all pull up pull down resistors are enabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5; // Ensure all pull up pull down resistors are disabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR6; // Ensure all pull up pull down resistors are disabled
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR7; // Ensure all pull up pull down resistors are disabled
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
SPI1->CR1 = 0;
SPI1->CFG1 = (3u << SPI_CFG1_MBR_Pos) |
(7u << SPI_CFG1_CRCSIZE_Pos) |
SPI_CFG1_TXDMAEN | // SPI_CFG1_RXDMAEN |
(7u << SPI_CFG1_FTHLV_Pos) |
(7u << SPI_CFG1_DSIZE_Pos)
;
SPI1->CFG2 = SPI_CFG2_SSOE |
SPI_CFG2_MASTER
;
//SPI1->CR2 |= 3;
SPI1->CR1 |= SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_CSTART;
DMA1_Stream0->CR |= DMA_SxCR_EN;
}</font>
复制代码
本质上,它是一回事,唯一的区别是有一个InitializeDMA功能,DMA传输是通过DMA1_Stream0->CR |= DMA_SxCR_EN命令启动的(就像之前的MCU系列中的情况一样)。所以,遗憾的是,我仍然无法通过H7上的DMA启动SPI。任何帮助将不胜感激。
友情提示:
此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
6条回答
hzp_bbs1
2019-07-15 10:55
好的,我会尽快尝试重建这个项目。与此同时,您能否解释DMAMUX-CxCR寄存器中的SYNC_ID位和请求发生器寄存器(DMAMUX_RGxCR)?什么时候需要使用那些?此外,如何将DMA流“附加”到特定外设?在我上面的例子中,我选择了DMA2_Stream3和DMAMUX1_Channel0,但实际上没有一段代码将两者连接在一起。
加载中...
查看其它6个回答
一周热门
更多
>
相关问题
STM32F4上I2C(在PROTEUS中模拟)调试不通的问题
6 个回答
芯片供应紧张,准备换个MCU,MM32L系列替换STM32L系列的怎么样?
7 个回答
STM32同时使用两个串口进行数据收发时数据丢包的问题
5 个回答
STM32F103串口通信死机问题
4 个回答
STM32WLE5CC连接SX1268在LoRa模式下能与 SX1278互通吗?
2 个回答
相关文章
ST公司第一款无线低功耗单片机模块有效提高物联网设计生产效率
0个评论
如何实现对单片机寄存器的访问
0个评论
通过USB用STM32片内自带Bootloader下载程序及注意事项
0个评论
欲练此功必先自宫之STM32汇编启动,放慢是为了更好的前行
0个评论
×
关闭
采纳回答
向帮助了您的知道网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
STM32
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
×
付费偷看金额在0.1-10元之间
确定
×
关闭
您已邀请
0
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
一周热门 更多>