我有 STM32F7 Disco 板和 STM32F723IEK MCU。尝试从定时器触发 DMA 请求会导致 DMA 错误,但仅适用于连接到 DMA1 的 APB1 组(TIM2 到 TIM7 等)的定时器。对连接到 DMA2 的 TIM1 和 TIM8 执行相同操作可以正常工作。错误表现为在相应的 DMA LISR 或 HISR 寄存器中设置了 TEIFx 标志,并且在第一次事务处理后立即禁用 DMA。NDTR 寄存器减一。
根据数据表,TEIF 错误可能由“总线错误”触发。我将其理解为例如尝试访问无法从 DMA 总线访问的外围设备。然而,同样的设置在使用 DMA2 和 TIM1/TIM8 时效果很好,无需更改 DMA 地址。所以问题似乎与 DMA 请求有关,而不是数据事务本身。鉴于为 DMA1 定义了许多定时器通道,这肯定可以工作。
我试图改变 DMA 设置,但这没有任何区别。测试程序的相关部分如下。完整版https://github.com/ak-hard/stm32-dma-tim/blob/master/main.c只是稍大一些,除了 CMSIS 和 STM32 设备头之外没有依赖项。
我想知道是否有人可以评论或重现此问题。
const struct
{
TIM_TypeDef *tim;
DMA_TypeDef *dma;
DMA_Stream_TypeDef *stream;
unsigned channel;
} CFG = {
// uncomment the needed combination below, only TIM1 and TIM8 work
// TIM1, DMA2, DMA2_Stream5, 6
TIM8, DMA2, DMA2_Stream1, 7
// TIM2, DMA1, DMA1_Stream1, 3
// TIM2, DMA1, DMA1_Stream7, 3
// TIM3, DMA1, DMA1_Stream2, 5
// TIM4, DMA1, DMA1_Stream6, 2
// TIM5, DMA1, DMA1_Stream0, 6
// TIM5, DMA1, DMA1_Stream6, 6
// TIM6, DMA1, DMA1_Stream1, 7
// TIM7, DMA1, DMA1_Stream2, 1
// TIM7, DMA1, DMA1_Stream4, 1
};
enum
{
DMA_SxCR_DIR_P2M = 0,
DMA_SxCR_PSIZE_WORD = DMA_SxCR_PSIZE_1,
DMA_SxCR_MSIZE_WORD = DMA_SxCR_MSIZE_1,
};
#define DMA_SxCR_CHSEL_NUM(ch) ((ch) << DMA_SxCR_CHSEL_Pos)
uint32_t buf;
void start(void)
{
SysTick->LOAD = 0xffffffu;
SysTick->VAL = 0;
SysTick->CTRL = 5;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM8EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM4EN | RCC_APB1ENR_TIM5EN
| RCC_APB1ENR_TIM6EN | RCC_APB1ENR_TIM7EN;
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN | RCC_AHB1ENR_DMA2EN;
LED_PORT->MODER |= 1 << (2 * LED_PIN);
LED_PORT->OSPEEDR |= 3 << (2 * LED_PIN); // fastest speed
CFG.tim->CR1 |= TIM_CR1_ARPE;
CFG.tim->ARR = 16;
CFG.tim->PSC = 1000;
CFG.tim->EGR = TIM_EGR_UG; // Generate Update Event to copy ARR to its shadow
CFG.tim->DIER |= TIM_DIER_UDE;
CFG.stream->CR |= DMA_SxCR_CHSEL_NUM(CFG.channel) | DMA_SxCR_DIR_P2M | DMA_SxCR_PSIZE_WORD | DMA_SxCR_MSIZE_WORD;
CFG.stream->NDTR = 16;
CFG.stream->PAR = (uint32_t) &GPIOA->IDR;
CFG.stream->M0AR = (uint32_t) &buf;
CFG.stream->CR |= DMA_SxCR_EN;
CFG.tim->CR1 |= TIM_CR1_CEN;
// wait until DMA state changes
while (CFG.dma->LISR == 0 && CFG.dma->HISR == 0)
delay_ms(1);
// check for any TEIFx bits
int error = (CFG.dma->LISR | CFG.dma->HISR) & 0x02080208;
while (1)
{
LED_PORT->ODR ^= 1 << LED_PIN;
delay_ms(error ? 100 : 500);
}
}