在STM32H7 MCU上配置DMA请求多路复用器

2019-07-14 17:58发布

我最近使用新生产的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请求: 1.png 据我所知,DMA流到DMA通道映射不再是“硬连线”,它可以在H7系列中手动重新配置。正如手册所述,必须使用DMAMux1将DMA请求线路连接到DMA通道。不幸的是,DMAMUX配置在参考手册中描述得相当差。我还没有意识到如何准确DMA流,外设和DMA通道通过多路复用器互连。下面是一段代码,理想情况下应该是
  • 设置SPI1。
  • 设置DMA。

  • 启用DMA流以进行SPI TX传输
    1. <font size="4">RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN;   // Enable usage of GPIOA
    2. RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;

    3. GPIOA->MODER &= ~GPIO_MODER_MODER5;
    4. GPIOA->MODER |= GPIO_MODER_MODER5_1;   // Alternate function for SPI1 SCK on PA5
    5. GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5;   // High Speed on PA5
    6. GPIOA->AFR[0] |= (0x05 << 5 * 4);   // AFRL selected AF5 (SPI1 SCK) for PA5

    7. GPIOA->MODER &= ~GPIO_MODER_MODER6;
    8. GPIOA->MODER |= GPIO_MODER_MODER6_1;   // Alternate function for SPI1 MISO on PA6
    9. GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6;   // High Speed on PA6
    10. GPIOA->AFR[0] |= (0x05 << 6 * 4);   // AFRL selected AF5 (SPI1 MISO) for PA6

    11. GPIOA->MODER &= ~GPIO_MODER_MODER7;
    12. GPIOA->MODER |= GPIO_MODER_MODER7_1;   // Alternate function for SPI1 MOSI on PA7
    13. GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7;   // High Speed on PA7
    14. GPIOA->AFR[0] |= (0x05 << 7 * 4);   // AFRL selected AF5 (SPI1 MOSI) for PA7

    15. GPIOA->MODER &= ~GPIO_MODER_MODER4;
    16. GPIOA->MODER |= GPIO_MODER_MODER4_1;   // Alternate function for SPI1 NSS on PA7
    17. GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR4;   // High Speed on PA7
    18. GPIOA->AFR[0] |= (0x05 << 4 * 4);   // AFRL selected AF5 (SPI1 NSS) for PA7

    19. GPIOA->PUPDR |= GPIO_PUPDR_PUPDR4_0;  // Ensure all pull up pull down resistors are enabled
    20. GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5;   // Ensure all pull up pull down resistors are disabled
    21. GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR6;   // Ensure all pull up pull down resistors are disabled
    22. GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR7;   // Ensure all pull up pull down resistors are disabled

    23. SPI1->CFG1 = (1u << SPI_CFG1_MBR_Pos) | // Master baud rate: master clock / 2
    24.                  (7u << SPI_CFG1_CRCSIZE_Pos) | // Length of CRC frame
    25.                  SPI_CFG1_TXDMAEN | SPI_CFG1_RXDMAEN | // Enable RX/TX DMA
    26.                  (7u << SPI_CFG1_FTHLV_Pos) | // FIFO threshold level
    27.                  (7u << SPI_CFG1_DSIZE_Pos) //Number of bits in at single SPI data frame
    28.                  ;

    29. SPI1->CFG2 = SPI_CFG2_SSOE | // SS output enable
    30.              SPI_CFG2_MASTER // SPI Master
    31.              ;      

    32. RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;   // DMA2 clock enable;

    33. DMA2_Stream3->CR = 0u;
    34. DMA2_Stream3->PAR = (uint32_t) &(SPI1->TXDR);
    35. DMA2_Stream3->M0AR = (uint32_t) &(Data_Buffer[0]);
    36. DMA2_Stream3->CR |= (1u << DMA_SxCR_DIR_Pos);
    37. DMA2_Stream3->CR |= DMA_SxCR_MINC;
    38. DMA2_Stream3->CR |= DMA_SxCR_PL;
    39. DMA2_Stream3->NDTR = 1000;

    40. // 5. Use DMAMux1 to route a DMA request line to the DMA channel.
    41. DMAMUX1_Channel0->CCR  = (37u << DMAMUX_CxCR_DMAREQ_ID_Pos);

    42. SPI1->CR1 |= SPI_CR1_SPE;
    43. DMA2_Stream3->CR |= DMA_SxCR_EN;</font>
    复制代码
    此代码编译,我可以将其上传到STM32H753ZIT6 MCU。完整的代码还有PLL设置,它不包含在上面的代码段中(PLL初始化工作得很好,因为我能够探测MCO引脚上的400 MHz系统时钟)。DMA多路复用器设置无疑是不完整的。我只选择了一个适当的多路复用器输入资源。我甚至不确定多路复用器通道是否正确(或者他们的选择在H7 MCU中是否是任意的)。所以我的问题是为SPI TX传输设置DMA多路复用器的正确方法是什么?如果我可以运行这个MWE,我或多或少能够完成我的其余代码的迁移。
    所以,我一直在尝试关注user9403409的建议,但不幸的是,我无法走得太远。我仍然无法让SPI在H7系列微控制器上通过DMA工作。现在我可以让SPI在没有H7的DMA的情况下正常工作:
    1. <font size="4">#include "stm32h7xx.h"

    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include <string.h>

    5. static void InitializeMCO(void);
    6. static void ConfigureHSI(void);
    7. static void InitializeMasterTxSPI(void);
    8. uint8_t s_TransferBuffer[10];

    9. int main()
    10. {        
    11.     s_TransferBuffer[0] = 0xAA;
    12.     s_TransferBuffer[1] = 0xBB;
    13.     s_TransferBuffer[2] = 0xCC;

    14.     ConfigureHSI();
    15.     InitializeMCO();
    16.     InitializeMasterTxSPI();
    17.     while(1){};
    18. }

    19. static void ConfigureHSI(void)
    20. {
    21.     PWR->CR3 |= PWR_CR3_SCUEN;
    22.     PWR->D3CR |= (PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0);
    23.         while ((PWR->D3CR & PWR_D3CR_VOSRDY) != PWR_D3CR_VOSRDY)
    24.         {
    25.         };

    26.     FLASH->ACR = FLASH_ACR_LATENCY_2WS;

    27.     RCC->CR |= RCC_CR_HSION;
    28.     while ((RCC->CR & RCC_CR_HSIRDY) != RCC_CR_HSIRDY)
    29.     {
    30.     };

    31.     RCC->PLLCKSELR = (4u << RCC_PLLCKSELR_DIVM1_Pos) |
    32.                          (32u << RCC_PLLCKSELR_DIVM2_Pos) |
    33.                          (32u << RCC_PLLCKSELR_DIVM3_Pos) |
    34.                          RCC_PLLCKSELR_PLLSRC_HSI
    35.                          ;

    36.     RCC->PLLCFGR   =  RCC_PLLCFGR_DIVR1EN |
    37.                       RCC_PLLCFGR_DIVQ1EN |
    38.                       RCC_PLLCFGR_DIVP1EN |
    39.                       (2u << RCC_PLLCFGR_PLL1RGE_Pos)  |
    40.                       (1u << RCC_PLLCFGR_PLL1VCOSEL_Pos)
    41.                       ;

    42.     RCC->PLL1DIVR = ((2u - 1u) << RCC_PLL1DIVR_R1_Pos) |         
    43.         ((2u - 1u) << RCC_PLL1DIVR_Q1_Pos) |
    44.         ((2u - 1u) << RCC_PLL1DIVR_P1_Pos) |
    45.         ((10u - 1u) << RCC_PLL1DIVR_N1_Pos)  // Reducing the clock rate so I can probe it with my slow USB scope
    46.         ;

    47.     RCC->D1CFGR = RCC_D1CFGR_D1CPRE_DIV1;
    48.     RCC->D1CFGR = RCC_D1CFGR_HPRE_DIV2 |
    49.                   RCC_D1CFGR_D1PPRE_DIV2;
    50.     RCC->D2CFGR = RCC_D2CFGR_D2PPRE1_DIV2 |
    51.                   RCC_D2CFGR_D2PPRE2_DIV2;
    52.     RCC->D3CFGR = RCC_D3CFGR_D3PPRE_DIV2;

    53.     RCC->CR |= RCC_CR_PLL1ON;
    54.     while (!(RCC->CR & RCC_CR_PLLRDY))
    55.     {
    56.     };

    57.     RCC->CFGR |= (1u << 25);
    58.     RCC->CFGR |= RCC_CFGR_SW_PLL1;
    59.     while (!(RCC->CFGR & RCC_CFGR_SWS_PLL1))
    60.     {
    61.     };
    62. }

    63. /* Displays MCO on PC9 */
    64. static void InitializeMCO(void)
    65. {
    66.     RCC->CFGR |= RCC_CFGR_MCO2;
    67.         RCC->CFGR |= (15 << 25); // Reducing the output so I can probe it with my slow USB scope

    68.     RCC->AHB4ENR &= ~RCC_AHB4ENR_GPIOCEN;
    69.     RCC->AHB4ENR |= RCC_AHB4ENR_GPIOCEN;

    70.     GPIOC->MODER &= ~GPIO_MODER_MODER9;
    71.     GPIOC->MODER |= GPIO_MODER_MODER9_1;

    72.     GPIOC->OTYPER &= ~GPIO_OTYPER_OT_9;
    73.     GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR9;

    74.     GPIOC->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR9;
    75.     GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;

    76.     GPIOC->AFR[0] &= ~GPIO_AFRL_AFRL0;
    77. }

    78. static void InitializeMasterTxSPI(void)
    79. {
    80.     RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN;   // Enable usage of GPIOA

    81.     GPIOA->MODER &= ~GPIO_MODER_MODER5;
    82.     GPIOA->MODER |= GPIO_MODER_MODER5_1;   // Alternate function for SPI1 SCK on PA5
    83.     GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5;   // High Speed on PA5
    84.     GPIOA->AFR[0] |= (0x05 << 5 * 4);   // AFRL selected AF5 (SPI1 SCK) for PA5

    85.     GPIOA->MODER &= ~GPIO_MODER_MODER6;
    86.     GPIOA->MODER |= GPIO_MODER_MODER6_1;   // Alternate function for SPI1 MISO on PA6
    87.     GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6;   // High Speed on PA6
    88.     GPIOA->AFR[0] |= (0x05 << 6 * 4);   // AFRL selected AF5 (SPI1 MISO) for PA6

    89.     GPIOA->MODER &= ~GPIO_MODER_MODER7;
    90.     GPIOA->MODER |= GPIO_MODER_MODER7_1;   // Alternate function for SPI1 MOSI on PA7
    91.     GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7;   // High Speed on PA7
    92.     GPIOA->AFR[0] |= (0x05 << 7 * 4);   // AFRL selected AF5 (SPI1 MOSI) for PA7

    93.     GPIOA->MODER &= ~GPIO_MODER_MODER4;
    94.     GPIOA->MODER |= GPIO_MODER_MODER4_1;   // Alternate function for SPI1 NSS on PA7
    95.     GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR4;   // High Speed on PA7
    96.     GPIOA->AFR[0] |= (0x05 << 4 * 4);   // AFRL selected AF5 (SPI1 NSS) for PA7

    97.     GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR4;  // Ensure all pull up pull down resistors are enabled
    98.     GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5;   // Ensure all pull up pull down resistors are disabled
    99.     GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR6;   // Ensure all pull up pull down resistors are disabled
    100.     GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR7;   // Ensure all pull up pull down resistors are disabled

    101.     RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;

    102.     SPI1->CR1 = 0;

    103.     SPI1->CFG1 = (3u << SPI_CFG1_MBR_Pos) |
    104.                  (7u << SPI_CFG1_CRCSIZE_Pos) |
    105.                  //SPI_CFG1_TXDMAEN | // SPI_CFG1_RXDMAEN |
    106.                  (7u << SPI_CFG1_FTHLV_Pos) |
    107.                  (7u << SPI_CFG1_DSIZE_Pos)
    108.                  ;

    109.     SPI1->CFG2 = SPI_CFG2_SSOE |
    110.                  SPI_CFG2_MASTER
    111.                  ;      

    112.     SPI1->CR2 |= 3;
    113.     SPI1->CR1 |= SPI_CR1_SPE;
    114.     SPI1->CR1 |= SPI_CR1_CSTART;

    115.     for (uint32_t i=0; i<3; i++)
    116.     {
    117.             while ((SPI1->SR & SPI_SR_TXP) != SPI_SR_TXP){};
    118.             *((__IO uint32_t *)&SPI1->TXDR) = *((uint32_t *)&s_TransferBuffer[i]);
    119.     }
    120. }</font>
    复制代码
    上面的代码基本上做了三件事:
    • ConfigureHSI 初始化HSI时钟(我已经降低了时钟速度,以便能够使用我目前拥有的慢速USB示波器进行一些探测)。
    • InitializeMCO 显示主时钟输出(只是为了确保时钟配置正确)。
    • InitializeMasterTxSPI 配置SPI并发出三字节消息。

    我绝对可以看到在我的示波器上发送的消息: 2.png 时基为200 ns / div,供参考。
    另一方面,如果我尝试通过DMA重做整个事情,我看不到任何输出。这就是我的基于DMA的SPI代码:
    1. <font size="4">#include "stm32h7xx.h"
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include <string.h>

    5. static void InitializeMCO(void);
    6. static void ConfigureHSI(void);
    7. static void InitializeDMA(void);
    8. static void InitializeMasterTxSPI(void);
    9. uint8_t s_TransferBuffer[10];

    10. int main()
    11. {        
    12.     s_TransferBuffer[0] = 0xAA;
    13.     s_TransferBuffer[1] = 0xBB;
    14.     s_TransferBuffer[2] = 0xCC;

    15.     ConfigureHSI();
    16.     InitializeMCO();
    17.     InitializeDMA();
    18.     InitializeMasterTxSPI();
    19.     while(1){};
    20. }

    21. /* Initializes the MCU clock */
    22. static void ConfigureHSI(void)
    23. {
    24.     PWR->CR3 |= PWR_CR3_SCUEN;
    25.     PWR->D3CR |= (PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0);
    26.         while ((PWR->D3CR & PWR_D3CR_VOSRDY) != PWR_D3CR_VOSRDY)
    27.         {
    28.         };

    29.     FLASH->ACR = FLASH_ACR_LATENCY_2WS;

    30.     RCC->CR |= RCC_CR_HSION;
    31.     while ((RCC->CR & RCC_CR_HSIRDY) != RCC_CR_HSIRDY)
    32.     {
    33.     };

    34.     RCC->PLLCKSELR = (4u << RCC_PLLCKSELR_DIVM1_Pos) |
    35.                          (32u << RCC_PLLCKSELR_DIVM2_Pos) |
    36.                          (32u << RCC_PLLCKSELR_DIVM3_Pos) |
    37.                          RCC_PLLCKSELR_PLLSRC_HSI
    38.                          ;

    39.     RCC->PLLCFGR   =  RCC_PLLCFGR_DIVR1EN |
    40.                       RCC_PLLCFGR_DIVQ1EN |
    41.                       RCC_PLLCFGR_DIVP1EN |
    42.                       (2u << RCC_PLLCFGR_PLL1RGE_Pos)  |
    43.                       (1u << RCC_PLLCFGR_PLL1VCOSEL_Pos)
    44.                       ;

    45.     RCC->PLL1DIVR = ((2u - 1u) << RCC_PLL1DIVR_R1_Pos) |         
    46.         ((2u - 1u) << RCC_PLL1DIVR_Q1_Pos) |
    47.         ((2u - 1u) << RCC_PLL1DIVR_P1_Pos) |
    48.         ((10u - 1u) << RCC_PLL1DIVR_N1_Pos)  // Reducing the clock rate so I can probe it with my slow USB scope
    49.         ;

    50.     RCC->D1CFGR = RCC_D1CFGR_D1CPRE_DIV1;
    51.     RCC->D1CFGR = RCC_D1CFGR_HPRE_DIV2 |
    52.                   RCC_D1CFGR_D1PPRE_DIV2;
    53.     RCC->D2CFGR = RCC_D2CFGR_D2PPRE1_DIV2 |
    54.                   RCC_D2CFGR_D2PPRE2_DIV2;
    55.     RCC->D3CFGR = RCC_D3CFGR_D3PPRE_DIV2;

    56.     RCC->CR |= RCC_CR_PLL1ON;
    57.     while (!(RCC->CR & RCC_CR_PLLRDY))
    58.     {
    59.     };

    60.     RCC->CFGR |= (1u << 25);
    61.     RCC->CFGR |= RCC_CFGR_SW_PLL1;
    62.     while (!(RCC->CFGR & RCC_CFGR_SWS_PLL1))
    63.     {
    64.     };
    65. }

    66. /* Displays MCO on PC9 */
    67. static void InitializeMCO(void)
    68. {
    69.     RCC->CFGR |= RCC_CFGR_MCO2;
    70.     RCC->CFGR |= (15 << 25); // Reducing the output so I can probe it with my slow USB scope

    71.     RCC->AHB4ENR &= ~RCC_AHB4ENR_GPIOCEN;
    72.     RCC->AHB4ENR |= RCC_AHB4ENR_GPIOCEN;

    73.     GPIOC->MODER &= ~GPIO_MODER_MODER9;
    74.     GPIOC->MODER |= GPIO_MODER_MODER9_1;

    75.     GPIOC->OTYPER &= ~GPIO_OTYPER_OT_9;
    76.     GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR9;

    77.     GPIOC->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR9;
    78.     GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;

    79.     GPIOC->AFR[0] &= ~GPIO_AFRL_AFRL0;
    80. }

    81. static void InitializeDMA()
    82. {
    83.     RCC->AHB2ENR |= (0x7 << 29);  // Enable the SRAM
    84.     RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;   // DMA1 clock enable;

    85.     // Set the peripheral and memory addresses:
    86.     DMA1_Stream0->PAR = *((__IO uint32_t *)&SPI1->TXDR);
    87.     DMA1_Stream0->M0AR = *((uint32_t *)&s_TransferBuffer[0]);

    88.     DMA1_Stream0->CR = 0u;
    89.     DMA1_Stream0->CR |= (1u << DMA_SxCR_DIR_Pos); // Memory to peripheral
    90.     DMA1_Stream0->CR |= DMA_SxCR_MINC; // Memory increment mode
    91.     DMA1_Stream0->CR |= (3u << DMA_SxCR_PL_Pos); // Very high priority

    92.     DMA1_Stream0->NDTR = 3; // Number of data

    93.     DMAMUX1_Channel0->CCR  = (38u << DMAMUX_CxCR_DMAREQ_ID_Pos);

    94. }

    95. static void InitializeMasterTxSPI(void)
    96. {
    97.     RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN;   // Enable usage of GPIOA

    98.     GPIOA->MODER &= ~GPIO_MODER_MODER5;
    99.     GPIOA->MODER |= GPIO_MODER_MODER5_1;   // Alternate function for SPI1 SCK on PA5
    100.     GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5;   // High Speed on PA5
    101.     GPIOA->AFR[0] |= (0x05 << 5 * 4);   // AFRL selected AF5 (SPI1 SCK) for PA5

    102.     GPIOA->MODER &= ~GPIO_MODER_MODER6;
    103.     GPIOA->MODER |= GPIO_MODER_MODER6_1;   // Alternate function for SPI1 MISO on PA6
    104.     GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6;   // High Speed on PA6
    105.     GPIOA->AFR[0] |= (0x05 << 6 * 4);   // AFRL selected AF5 (SPI1 MISO) for PA6

    106.     GPIOA->MODER &= ~GPIO_MODER_MODER7;
    107.     GPIOA->MODER |= GPIO_MODER_MODER7_1;   // Alternate function for SPI1 MOSI on PA7
    108.     GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7;   // High Speed on PA7
    109.     GPIOA->AFR[0] |= (0x05 << 7 * 4);   // AFRL selected AF5 (SPI1 MOSI) for PA7

    110.     GPIOA->MODER &= ~GPIO_MODER_MODER4;
    111.     GPIOA->MODER |= GPIO_MODER_MODER4_1;   // Alternate function for SPI1 NSS on PA4
    112.     GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR4;   // High Speed on PA4
    113.     GPIOA->AFR[0] |= (0x05 << 4 * 4);   // AFRL selected AF5 (SPI1 NSS) for PA4

    114.     GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR4;  // Ensure all pull up pull down resistors are enabled
    115.     GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5;   // Ensure all pull up pull down resistors are disabled
    116.     GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR6;   // Ensure all pull up pull down resistors are disabled
    117.     GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR7;   // Ensure all pull up pull down resistors are disabled

    118.     RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;

    119.     SPI1->CR1 = 0;
    120.     SPI1->CFG1 = (3u << SPI_CFG1_MBR_Pos) |
    121.                  (7u << SPI_CFG1_CRCSIZE_Pos) |
    122.                  SPI_CFG1_TXDMAEN | // SPI_CFG1_RXDMAEN |
    123.                  (7u << SPI_CFG1_FTHLV_Pos) |
    124.                  (7u << SPI_CFG1_DSIZE_Pos)
    125.                  ;
    126.     SPI1->CFG2 = SPI_CFG2_SSOE |
    127.                  SPI_CFG2_MASTER
    128.                  ;      

    129.     //SPI1->CR2 |= 3;
    130.     SPI1->CR1 |= SPI_CR1_SPE;
    131.     SPI1->CR1 |= SPI_CR1_CSTART;

    132.     DMA1_Stream0->CR |= DMA_SxCR_EN;
    133. }</font>
    复制代码本质上,它是一回事,唯一的区别是有一个InitializeDMA功能,DMA传输是通过DMA1_Stream0->CR |= DMA_SxCR_EN命令启动的(就像之前的MCU系列中的情况一样)。所以,遗憾的是,我仍然无法通过H7上的DMA启动SPI。任何帮助将不胜感激。








友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
6条回答
hzp_bbs1
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编程的人。

一周热门 更多>