我有STM32F7 Disco板和STM32F723IEK MCU。尝试从定时器触发DMA请求会导致DMA错误,但仅适用于连接到DMA1的APB1组(TIM2到TIM7和其他)的定时器。对连接到DMA2的TIM1和TIM8执行相同操作也可以正常工作。错误表现为在相应的DMA LISR或HISR寄存器中设置TEIFx标志,并在第一次事务后立即禁用DMA。 NDTR寄存器递减1。
根据数据表,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);
}
}
答案 0 :(得分:2)
这里有一个答案,但由于某种原因它被删除了。感谢其作者。
查看总线矩阵,很明显DMA1的外围总线仅连接到APB1。它实际上根本不是矩阵的一部分。这可能意味着DMA1只能处理来自/到APB1外设的传输。由于GPIO是AHB外设,因此无法从DMA1访问它。这也适用于其他APB2(例如SPI1)和AHB外设(例如OTGFS)。通常,从DMA1访问AHB或APB2外设没有意义,因为它们的请求不会路由到DMA1。但是,计时器可能需要像GPIO这样的复杂情况。
我个人认为这一点可以在文档中更加明显。