如果您取消注释由 SysTick 计时器触发的通道 30 上的基本软件 DMA 传输,则 DMA 引擎会工作。但是 Timer1A 触发 DMA 到 SSI1-DR 使 DMA 引擎空闲。
我正在尝试将 16 位数据从 RAM 中的缓冲区发送到 SSI1 数据寄存器。我的 DMA 配置有什么地方不对吗?这是我第一次尝试使用 DMA,我无法理解源和目标的控制表配置。我基本上将 Jonathan Valvano 博士的 DMASPI.C 和 DMASoftware.c 重写到一个项目中。
我非常感谢对 dma 控制表设置和索引的解释。
博士Valvano的软件DMA代码链接:http://users.ece.utexas.edu/~valvano/arm/DMASoftware.c
博士Valvano 的其他代码,其中 DMASPI.c 在 zip 文件夹中:http://users.ece.utexas.edu/~valvano/arm/index.htm
这是C文件代码
#include "timer.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#define BIT30 0x40000000
#define CH30 (30*4)
#define CH30ALT (30*4+128)
#define SSI_DR_R *((volatile uint32_t *) 0x40009008)
#define BIT18 0x00040000
#define CH18SEL 0x00000200
#define CH18 (18*4)
#define CH18ALT (18*4+128)
static uint16_t *SourcePt;
static volatile uint32_t *DestinationPt;
static uint32_t Count;
static uint32_t BufferCount;
static uint32_t DMA_ControlTable[256]__attribute__ ((aligned(1024))); //uDMA Control Table
static uint32_t DMA_PingpongCTLTB[256]__attribute__ ((aligned(1024))); //uDMA Control Table
static uint32_t NumberOfBuffersSent=0;
uint8_t timerCounts=0xffff;
static uint16_t endPT = (131*8)-1 ;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/*
__ __ _ ___ _ _ ___ ___ _ _ _____ ___ _ _ ___
| \/ | /_\ |_ _| | \| | | _ \ / _ \ | | | | |_ _| |_ _| | \| | | __|
| |\/| | / _ \ | | | .` | | / | (_) | | |_| | | | | | | .` | | _|
|_| |_| /_/ \_\ |___| |_|\_| |_|_\ \___/ \___/ |_| |___| |_|\_| |___|
*//*__________________________________________________________________________________________________________________________________________*/
int main(void)
{
//main start
//timer1A_Init(0xffff);
F_init();
SPI1_init();
DMA_SourceStart();
// DMA_SimpleInit();
// DMA_SimpleStart(&DMA_SourceTest[0], &DMA_DestTest[0], 10);
// SysTick_INIT();
////timer1A_Init(0xffff);
DMA_PingpongInit(0xFFFF); //Arms Timer but doesn't enable it
// DMA_PingpongStart(&DMAPingpong_SourceTest[0], &DMA_DestTest[0], (100)); //enables: timer,timer interrupts, DMA Engine
// DMA_PingpongStart(&DMAPingpong_SourceTest[0], (uint32_t *)SSI_DR_R, (100)); //enables: timer,timer interrupts, DMA Engine
DMA_PingpongStart(&DMAPingpong_SourceTest[0], &(SSI1->DR), 10); //enables: timer,timer interrupts, DMA Engine
while(1)
{
WaitForInterrupt();
BufferCount = DMA_Status();
}
} /* MAIN END*/
/*-------------------------------- PORT F INIT --------------------------------------------*/
void F_init(void)
{
SYSCTL->RCGCGPIO |= (1<<5); /* Enable clock to GPIOF */
GPIOF->DEN |= (1<<3) | (1<<2)| (1<<1) ; /* Set PF3 pin digital */
GPIOF->DIR |= (1<<3) | (1<<2)| (1<<1) ; /* Set PF3 pin output */
GPIOF->DIR |= (1<<3) | (1<<2)| (1<<1); /* Set PF3 pin output */
GPIOF->DATA |= (1<<3) | (1<<2)| (1<<1); /* PF2 as Reset for OLED */
}
static void timer1A_Init(uint16_t period)
{
SYSCTL->RCGCTIMER |= 0x02;
TIMER1->CTL &=!(0x00000001);// Disable Timer for CFG
TIMER1->CFG =0x4; //16 BIT TIMER
TIMER1->TAMR = 0x02; //PERIODIC MODE
//TIMER1->TAILR =(0xFFFF-1);
TIMER1->TAPR =255-1; //prescaler (48MHz/(TAPR))
//TIMER1->TAPR =0;
TIMER1->TAILR =(period-1); // Releoad Value
TIMER1->ICR |=0x01; // Clear Interrupts
TIMER1->IMR |=0x01; // Timer1A timeout interrupr Enabled
NVIC->IP[TIMER1A_IRQn] |= 0x7; // timer1A priority level
// NVIC->ISER[0] |= (1<<21); //timer1A to NVIC
// TIMER1->CTL |=(0x00000001); //Enabled by DMA Start
}
/*_______________________________________________________________________________________________*/
void TIMER1A_Handler(void)
{
//DisableInterrupts(); // gloabal interrupt disable
NumberOfBuffersSent++;
GPIOF->DATA ^= (1<<3) | (1<<2)| (1<<1); //toggle LEDs
// UDMA->SWREQ |= BIT30; //udma software request
if((DMA_PingpongCTLTB[CH18+2]&0x0007)==0){ // regular buffer complete
DMA_SetRegular(); // rebuild channel control structure
}
if((DMA_PingpongCTLTB[CH18ALT+2]&0x0007)==0){ // Alternate buffer complete
DMA_SetAlt(); // rebuild channel control structure
}
TIMER1->ICR =0x01; //ACK timer timeout
//EnableInterrupts(); // gloabal interrupt enable
}
/*_______________________________________________________________________________________________*/
void SysTick_Handler(void) /* SysTick interrupt handler function*/
{
GPIOF->DATA ^= (1<<3) | (1<<2)| (1<<1);
UDMA->SWREQ |= BIT30;
}
/*_______________________________________________________________________________________________*/
void static DMA_SimpleInit(void)
{
for(uint16_t i=0; i<256; i++){
DMA_ControlTable[i] = 0;} // clear control table
SYSCTL->RCGCDMA |= 0x01; // DMA clocked
Delay_ms(1);
UDMA->CFG = 0x01; // enable Configuration
UDMA->CTLBASE = (uint32_t) DMA_ControlTable; // control table base
UDMA->CHMAP3 |= BIT30; // software DMA
UDMA->PRIOCLR |= BIT30;
UDMA->ALTCLR |= BIT30;
UDMA->USEBURSTCLR |= BIT30;
UDMA->REQMASKCLR |= BIT30;
}
/*_______________________________________________________________________________________________*/
void static DMA_SimpleStart(uint32_t *source, uint32_t *destination, uint32_t count)
{
/* DMACHCTL Bits Value Description
DSTINC 31:30 10 32-bit destination address increment
DSTSIZE 29:28 10 32-bit destination data size
SRCINC 27:26 10 32-bit source address increment
SRCSIZE 25:24 10 32-bit source data size
reserved 23:18 0 Reserved
ARBSIZE 17:14 0011 Arbitrates after 8 transfers
XFERSIZE 13:4 count-1 Transfer count items
NXTUSEBURST 3 0 N/A for this transfer type
XFERMODE 2:0 010 Use Auto-request transfer mode
*/
/*__________________________________*/
DMA_ControlTable[CH30] = (uint32_t)source+count*4-1 ;
DMA_ControlTable[CH30+1] = (uint32_t )destination+count*4-1 ;
//DMA_ControlTable[2] = (uint32_t)((0x00000000)|(0<<28)|(0<<26)|(0<<24)|(1<<14)|(1024<<4)|(0<<3)|(1<<0));
DMA_ControlTable[CH30+2] = 0xAA00C002+((count-1)<<4);
UDMA->ENASET |= BIT30;
// UDMA->SWREQ |= BIT30;
}
/*_______________________________________________________________________________________________*/
void static DMA_PingpongInit(uint16_t period)
{
for(uint16_t i=0; i<256; i++){
DMA_ControlTable[i] = 0;}
SYSCTL->RCGCDMA = 0x01; // CLOCK DMA engine
Delay_ms(1);
UDMA->CFG = 0x01; // enable configuration
UDMA->CTLBASE = (uint32_t) DMA_PingpongCTLTB;
UDMA->CHMAP2 = CH18SEL; // select channel 18 bit 1 for timer1A DMA Trigger
UDMA->PRIOCLR = BIT18;
UDMA->ALTCLR = BIT18;
UDMA->USEBURSTCLR = BIT18;
UDMA->REQMASKCLR = BIT18;
timer1A_Init(period);
}
/*_______________________________________________________________________________________________*/
void static DMA_SetRegular(void)
{
/* DMACHCTL Bits Value Description
DSTINC 31:30 11 no destination address increment
DSTSIZE 29:28 01 16-bit destination data size
SRCINC 27:26 01 16-bit source address increment
SRCSIZE 25:24 01 16-bit source data size
reserved 23:18 0 Reserved
ARBSIZE 17:14 0 Arbitrates after 1 transfers
XFERSIZE 13:4 count-1 Transfer count items
NXTUSEBURST 3 0 N/A for this transfer type
XFERMODE 2:0 011 Use PINGPONG transfer mode
*/
DMA_PingpongCTLTB[CH18] = (uint32_t)SourcePt;
DMA_PingpongCTLTB[CH18+1] = (uint32_t )DestinationPt;
//DMA_PingpongCTLTB[CH18ALT+2] = 0xA500C003+((Count-1)<<4);
DMA_PingpongCTLTB[CH18+2] = 0xD5000003+((Count-1)<<4);
}
/*_______________________________________________________________________________________________*/
void static DMA_SetAlt(void)
{
/* DMACHCTL Bits Value Description
DSTINC 31:30 11 no destination address increment
DSTSIZE 29:28 01 16-bit destination data size
SRCINC 27:26 01 16-bit source address increment
SRCSIZE 25:24 01 16-bit source data size
reserved 23:18 0 Reserved
ARBSIZE 17:14 0 Arbitrates after 1 transfers
XFERSIZE 13:4 count-1 Transfer count items
NXTUSEBURST 3 0 N/A for this transfer type
XFERMODE 2:0 011 Use PINGPONG transfer mode
*/
DMA_PingpongCTLTB[CH18ALT] = (uint32_t)SourcePt;
DMA_PingpongCTLTB[CH18ALT+1] = (uint32_t )DestinationPt;
//DMA_PingpongCTLTB[CH18ALT+2] = 0xA500C003+((Count-1)<<4);
DMA_PingpongCTLTB[CH18ALT+2] = 0xD5000003+((Count-1)<<4);
}
/*_______________________________________________________________________________________________*/
void static DMA_PingpongStart(uint16_t *source,volatile uint32_t*destination, uint32_t count)
{
SourcePt = (source +count)-1;
DestinationPt = destination;
Count = count;
DMA_SetRegular();
DMA_SetAlt();
NVIC->ISER[0] |= (1<<21); // timer1A to NVIC
SSI1->DMACTL |= 0x02; // SSI1 uDMA for Tx FIFO Enabled
UDMA->ENASET |= BIT18; // Arm DMA Engine
TIMER1->CTL |=(0x00000001); // timer1A ENABLE
}
/*_______________________________________________________________________________________________*/
void static DMA_SourceStart(void)
{
int i;
uint32_t *sourcePTR;
for(i = 0 ; i < (131*8); i++)
{
sourcePTR = &DMA_SourceTest[i];
*sourcePTR = 0xFF;
DMAPingpong_SourceTest[i] = 0x0FFF;
}
}
/*_______________________________________________________________________________________________*/
uint32_t DMA_Status(void){
return NumberOfBuffersSent;
}
这是糟糕的 .H 文件代码
#include "TM4C123GH6PM.h"
void static DMA_SimpleInit(void);
void static DMA_PingpongInit(uint16_t period);
void SPI1_init(void);
void F_init(void);
/*init timers */
static void timer1A_Init(uint16_t period);
void SysTick_INIT(void);
/* timer interrupt handler*/
void TIMER1A_Handler(void);
void SysTick_Handler(void);
void DisableInterrupts(void);
void EnableInterrupts(void);
void WaitForInterrupt(void);
void Delay_ms(int time_ms);
/* uDMA Functions*/
void static DMA_SourceStart(void);
void static DMA_SimpleStart(uint32_t *source,uint32_t*destination, uint32_t count);
void static DMA_PingpongStart(uint16_t *source,volatile uint32_t*destination, uint32_t count);
uint32_t DMA_Status(void);
void static DMA_SetRegular(void);
void static DMA_SetAlt (void);
static uint32_t DMA_SourceTest [131*8];
static uint16_t DMAPingpong_SourceTest [131*8];
static uint32_t DMA_DestTest [131*8];
void Delay_ms(int time_ms)
{
int i, j;
for(i = 0 ; i < time_ms; i++)
{
for(j = 0; j < 20; j++){} /* excute NOP for 0.5ms */
}
}
void SysTick_INIT(void)
{
//SysTick->LOAD = 47999;
//SysTick->LOAD = 23999; /* about 500 ns @ 48 MHz */
SysTick->LOAD = 15999999;
//SysTick->LOAD = sysVal;
//SysTick->LOAD = (7800000);
//SysTick->LOAD = (3800000);
//SysTick->LOAD = (1500000);
//NVIC->IP[SysTick_IRQn] |= (1<<7); /*set portE interrupt priority*/
//NVIC->ISER[0] |= (1<<4); /* Enable portE interrupts*/
//SysTick->LOAD = timer_Val;
SysTick->CTRL|= 0x07;
SysTick->VAL |= 0x00;
}
void DisableInterrupts(void)
{
__asm (" CPSID I\n");
}
/*********** EnableInterrupts ***************
*
* emable interrupts
*
* inputs: none
* outputs: none
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void EnableInterrupts(void)
{
__asm (" CPSIE I\n");
}
/*********** WaitForInterrupt ************************
*
* go to low power mode while waiting for the next interrupt
*
* inputs: none
* outputs: none
*/
void WaitForInterrupt(void)
{
__asm (" WFI\n");
}
void SPI1_init(void)
{
/*_______________________________________________________________________________________________________________*/
/* Enable clock to SPI1, GPIOD and GPIOF */
SYSCTL->RCGCSSI |= (1<<1); /*set clock enabling bit for SPI1 */
SYSCTL->RCGCGPIO |= (1<<3); /* enable clock to GPIOD for SPI1 */
SYSCTL->RCGCGPIO |= (1<<5); /* enable clock to GPIOF for slave select */
/*_______________________________________________________________________________________________________________*/
/* Initialize PF3 as a digital output as a slave select pin */
/* GPIOF->AMSEL &= 0x00; disable analog functionality Port F */
// GPIOF->AFSEL |= 0x08; /* enable alternate function of PF3 */
// GPIOF->PCTL |= 0x00002000; /* assign PF3 to SPI1 */
GPIOF->DEN |= (1<<3) | (1<<2)| (1<<1) ; /* set PF3 pin digital */
//GPIOF->DR4R |= (1<<3) | (1<<2)| (1<<1); /* set PF[3-1] 4mA */
GPIOF->DIR |= (1<<3) | (1<<2)| (1<<1) ; /* set PF3 pin output */
GPIOF->DATA |= (1<<3); /* keep SS idle high */
/*_______________________________________________________________________________________________________________*/
/*Initialize PD3 and PD0 for SPI1 alternate function*/
/*GPIOD->AMSEL &= 0x00; disable analog functionality PD0 and PD3 */
GPIOD->AFSEL |= 0x09; /* enable alternate function of PD0 and PD3*/
/*GPIOD->PCTL &= 0x0000F00F; assign PD0 and PD3 pins to SPI1 */
GPIOD->PCTL |= 0x00002002; /* assign PD0 and PD3 pins to SPI1 */
GPIOD->DR8R |= (1<<3)|(1<<0);
GPIOD->DEN |= 0x09; /* Set PD0 and PD3 as digital pin */
/*GPIOD->DIR |= 0x09; Set PD0 and PD3 as digital OUTPUT pins */
/*_______________________________________________________________________________________________________________*/
/* Select SPI1 as a Master, POL = 0, PHA = 0, clock = 4 MHz, 8 bit data */
/*SSI1->CR1 &= 0x00; disable SPI1 and configure it as a Master */
SSI1->CR1 &= 0x00000000; /* disable SPI1 and configure it as a Master */
SSI1->CC |= 0x00; /* Enable System clock Option */
SSI1->CPSR |= 6; /* Select prescaler .i.e 48MHz/16 = 3MHz | 48MHz/8 = 6~8MHz | 48MHz/4 = 8~12MHz*/
SSI1->CR0 |= 0xF; /* XMHz SPI1 clock, SPI mode, 8 bit data */
//SSI1->DMACTL |= 0x02; // SSI1 uDMA for Tx FIFO Enabled
// SSI1->IM |= 0x08;
//
// NVIC->IP[SSI1_IRQn] |= 0x01 ;
// NVIC->ISER[1] |= 0x04;
/*________________________________________________________*/
/*Initialize SPI1 uDMA functionality*/
//SSI1->DMACTL->0x2;
//EOT interrupt
// SSI1->CR1 |= (1<<4)|(1<<1); /* enable SPI1 */
SSI1->CR1 |= (1<<1); /* enable SPI1 */
}
此外,我不确定将 SSI1-DMACTL 部分放在哪里。
我使用 Keil uVision5 单步执行代码,DMA 控制表设置中的所有内容都设置正确。 DMA_PingpongStart(&DMAPingpong_SourceTest[0], &(SSI1->DR), 10);功能武装一切,甚至定时器中断切换 LED,但 SSI1->DR(SSI1 数据寄存器)中没有任何显示。