专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
STM32
在STM32H7 MCU上配置DMA请求多路复用器
2019-07-14 17:58
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
STM32/STM8
14430
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
1楼-- · 2019-07-15 04:54
你能详细说明吗?这不是: // 5. Use DMAMux1 to route a DMA request line to the DMA channel. DMAMUX1_Channel0->CCR = (37u << DMAMUX_CxCR_DMAREQ_ID_Pos); 行吗?
加载中...
sjjs001
2楼-- · 2019-07-15 05:42
精彩回答 2 元偷偷看……
加载中...
hzp_bbs1
3楼-- · 2019-07-15 10:55
好的,我会尽快尝试重建这个项目。与此同时,您能否解释DMAMUX-CxCR寄存器中的SYNC_ID位和请求发生器寄存器(DMAMUX_RGxCR)?什么时候需要使用那些?此外,如何将DMA流“附加”到特定外设?在我上面的例子中,我选择了DMA2_Stream3和DMAMUX1_Channel0,但实际上没有一段代码将两者连接在一起。
加载中...
sjjs001
4楼-- · 2019-07-15 14:37
只是dmamux1_channel0硬连线到dma1_stream0,dmamux1_channel8到dma2_stream0等等。它需要从一个事件源同步启动多个dma。
加载中...
hzp_bbs1
5楼-- · 2019-07-15 17:11
我设法让SPI DMA运行。在下面发布我的工作代码:
#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);
const uint8_t aTxBuffer[] = "Simple SPI message";
int main()
{
ConfigureHSI();
InitializeMCO();
InitializeDMA();
InitializeMasterTxSPI();
while (1)
{
/* Delay added to distinguish between the SPI messages: */
while(DMA2_Stream4->NDTR != 0) asm("nop");
for(uint32_t i=0; i<0xBF; i++) asm("nop");
//DMA2_Stream4->CR &= ~DMA_SxCR_EN;
DMA2->HIFCR |= DMA_HIFCR_CTCIF4 | DMA_HIFCR_CHTIF4 | DMA_HIFCR_CTEIF4 | DMA_HIFCR_CDMEIF4 | DMA_HIFCR_CFEIF4;
//DMA2_Stream4->PAR = (uint32_t) &(SPI1->TXDR);
DMA2_Stream4->M0AR = (uint32_t ) &(aTxBuffer[0]);
DMA2_Stream4->NDTR = 0x12;
DMA2_Stream4->CR |= DMA_SxCR_EN;
};
}
/* 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 |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN | RCC_AHB2ENR_D2SRAM3EN); // Enable the SRAM
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; // DMA2 clock enable;
// Set the peripheral and memory addresses:
DMA2_Stream4->PAR = (uint32_t) &(SPI1->TXDR);
DMA2_Stream4->M0AR = (uint32_t ) &(aTxBuffer[0]);
DMA2_Stream4->CR = 0;
DMA2_Stream4->CR |= (1u << DMA_SxCR_DIR_Pos); // Memory to peripheral
DMA2_Stream4->CR |= DMA_SxCR_MINC; // Memory increment mode
DMA2_Stream4->CR |= (3u << DMA_SxCR_PL_Pos); // Very high priority
DMA2_Stream4->NDTR = 0x12; //DMA transfer length
DMA2_Stream4->CR |= DMA_SxCR_EN; // Enable DMA stream
DMAMUX1_Channel12->CCR = 0x26;
}
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 = SPI_CR1_SSI;
SPI1->CFG1 = (2u << 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_SSM | SPI_CFG2_MASTER;
SPI1->CR1 |= SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_CSTART;
}
复制代码
加载中...
hzp_bbs1
6楼-- · 2019-07-15 20:51
现在考虑所有事情,DMAMUX的基本功能并不太难。手册指出:
DMAMUX1通道0到7连接到DMA1通道0到7
DMAMUX1通道8至15连接到DMA2通道0至7
DMAMUX2通道0到7连接到BDMA通道0到7
这些以及多路复用器输入到资源表的分配是使DMA运行的关键(至少以与旧系列MCUS相同的方式运行)。例如,SPI1_TX位于DMAMUX1的第38个DMA请求MUX输入上(参见参考手册中的表110)。这意味着我可以使用DMA1或DMA2(而不是BDMA,因为它链接到DMAMUX2)。我可以选择我想要的任何流,他们只需要遵循以下规则:
DMA1_Stream_x - > DMAMUX1_Channel_x
DMA2_Stream_x - > DMAMUX1_Channel_(x + 8)
因此,这就是通过DMAMUX的特定通道将外设实际链接到DMA流的方式。
还有几点需要注意:
不要忘记设置SPI_CR1_CSTART位(这是H7的新功能)。
注意SPI->CR2寄存器。如果为其写入值,则SPI传输将在预定义的数据传输开始后停止。如果我设置了CR2,那么无限循环(如我的示例所示)将无法工作(我们只会获得一次完整的SPI传输)。
虽然现在整个事情对我来说似乎有点明显,但我仍觉得参考文献中的信息有些缺乏。旧系列手册中的DMA操作稍微好一点。例如,我仍然不知道如何(以及何时)利用DMAMUX的剩余功能(如请求生成器和诸如此类)。此外,我不太确定如何实现内存到内存的传输。
我希望这有助于任何想深入研究ARM编程的人。
加载中...
一周热门
更多
>
相关问题
STM32F4上I2C(在PROTEUS中模拟)调试不通的问题
6 个回答
芯片供应紧张,准备换个MCU,MM32L系列替换STM32L系列的怎么样?
7 个回答
STM32同时使用两个串口进行数据收发时数据丢包的问题
5 个回答
STM32F103串口通信死机问题
4 个回答
STM32WLE5CC连接SX1268在LoRa模式下能与 SX1278互通吗?
2 个回答
STM32开发板免费用活动
7 个回答
stm32 处理 DHT11占用太多时间,大家程序是怎么设计的
8 个回答
分享一个STM32单片机做的离线编程器代码
9 个回答
相关文章
ST公司第一款无线低功耗单片机模块有效提高物联网设计生产效率
0个评论
如何实现对单片机寄存器的访问
0个评论
通过USB用STM32片内自带Bootloader下载程序及注意事项
0个评论
欲练此功必先自宫之STM32汇编启动,放慢是为了更好的前行
0个评论
×
关闭
采纳回答
向帮助了您的网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
STM32
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
关闭
您已邀请
15
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
- #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);
- const uint8_t aTxBuffer[] = "Simple SPI message";
- int main()
- {
- ConfigureHSI();
- InitializeMCO();
- InitializeDMA();
- InitializeMasterTxSPI();
- while (1)
- {
- /* Delay added to distinguish between the SPI messages: */
- while(DMA2_Stream4->NDTR != 0) asm("nop");
- for(uint32_t i=0; i<0xBF; i++) asm("nop");
- //DMA2_Stream4->CR &= ~DMA_SxCR_EN;
- DMA2->HIFCR |= DMA_HIFCR_CTCIF4 | DMA_HIFCR_CHTIF4 | DMA_HIFCR_CTEIF4 | DMA_HIFCR_CDMEIF4 | DMA_HIFCR_CFEIF4;
- //DMA2_Stream4->PAR = (uint32_t) &(SPI1->TXDR);
- DMA2_Stream4->M0AR = (uint32_t ) &(aTxBuffer[0]);
- DMA2_Stream4->NDTR = 0x12;
- DMA2_Stream4->CR |= DMA_SxCR_EN;
- };
- }
- /* 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 |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN | RCC_AHB2ENR_D2SRAM3EN); // Enable the SRAM
- RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; // DMA2 clock enable;
- // Set the peripheral and memory addresses:
- DMA2_Stream4->PAR = (uint32_t) &(SPI1->TXDR);
- DMA2_Stream4->M0AR = (uint32_t ) &(aTxBuffer[0]);
- DMA2_Stream4->CR = 0;
- DMA2_Stream4->CR |= (1u << DMA_SxCR_DIR_Pos); // Memory to peripheral
- DMA2_Stream4->CR |= DMA_SxCR_MINC; // Memory increment mode
- DMA2_Stream4->CR |= (3u << DMA_SxCR_PL_Pos); // Very high priority
- DMA2_Stream4->NDTR = 0x12; //DMA transfer length
- DMA2_Stream4->CR |= DMA_SxCR_EN; // Enable DMA stream
- DMAMUX1_Channel12->CCR = 0x26;
- }
- 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 = SPI_CR1_SSI;
- SPI1->CFG1 = (2u << 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_SSM | SPI_CFG2_MASTER;
- SPI1->CR1 |= SPI_CR1_SPE;
- SPI1->CR1 |= SPI_CR1_CSTART;
- }
复制代码DMAMUX1通道0到7连接到DMA1通道0到7
DMAMUX1通道8至15连接到DMA2通道0至7
DMAMUX2通道0到7连接到BDMA通道0到7
这些以及多路复用器输入到资源表的分配是使DMA运行的关键(至少以与旧系列MCUS相同的方式运行)。例如,SPI1_TX位于DMAMUX1的第38个DMA请求MUX输入上(参见参考手册中的表110)。这意味着我可以使用DMA1或DMA2(而不是BDMA,因为它链接到DMAMUX2)。我可以选择我想要的任何流,他们只需要遵循以下规则:
DMA1_Stream_x - > DMAMUX1_Channel_x
DMA2_Stream_x - > DMAMUX1_Channel_(x + 8)
因此,这就是通过DMAMUX的特定通道将外设实际链接到DMA流的方式。
还有几点需要注意:
不要忘记设置SPI_CR1_CSTART位(这是H7的新功能)。
注意SPI->CR2寄存器。如果为其写入值,则SPI传输将在预定义的数据传输开始后停止。如果我设置了CR2,那么无限循环(如我的示例所示)将无法工作(我们只会获得一次完整的SPI传输)。
虽然现在整个事情对我来说似乎有点明显,但我仍觉得参考文献中的信息有些缺乏。旧系列手册中的DMA操作稍微好一点。例如,我仍然不知道如何(以及何时)利用DMAMUX的剩余功能(如请求生成器和诸如此类)。此外,我不太确定如何实现内存到内存的传输。
我希望这有助于任何想深入研究ARM编程的人。
一周热门 更多>