📄 dualdma.c
字号:
/***************************************************************************
FILE NAME: DUALDMA.C
FILE DESCRIPTION: DUALDMA (Direct Memory Acces with the PC's DMA chip)
Sample program that demonstrates how to use dual DMA transfers.
This program transfers data using two DMA channels. When the first DMA
buffer is full, the board will automatically switch to the second DMA
buffer and continue acquiring data. The program then writes the first
buffer to a file. When the second buffer is full, the board switches
back to the first and the program writes the second buffer to the file.
Since the DMA controller is programmed for autoinitialize, the data
acquisition continues with no gaps.
1. Make two DMA buffers.
2. Program DMA controller.
3 Set up board pacer clock,channel,gain,triggers and dual DMA.
4. Program the interrupt controller to interrupt on DMA done.
5. On DMA done write Buffer to disk.
PROJECT NAME: DUALDMA (Part of DM6430 DOS Driver)
DRIVER VERSION: 1.1
COMPILER: Borland C++ 3.1
TARGET: Real-Mode DOS
Copyright 2003 RTD Embedded Technologies
***************************************************************************/
#include <alloc.h>
#include <conio.h>
#include <dos.h>
#include <mem.h>
#include <stdio.h>
#include "drvr6430.h"
#include "dio5812.h"
#include "dmautil.h"
#include "pcutil.h"
#include "vgraph.h"
/***************************************************************************
Defines
Change these constants to alter the program parameters.
****************************************************************************/
#define DMA_BUF_SIZE 10000l // The size of the DMA buffer (32768 max).
#define BASE_ADDRESS 768 // Base address.
#define CHANNEL 0 // A/D channel.
#define GAIN 0 // Gain.
#define SE_DIFF 0 // Single ended.
#define RATE 100000.0 // Sampling rate.
#define ADDMAChannel1 6 // First DMA Channel.
#define ADDMAChannel2 7 // Second DMA Channel.
#define IRQ_CHANNEL 10 // IRQ Channel.
// To set DMA Mode Register
#define MODE_REGISTER (DMA_AUTOINITIALIZATION | DMA_DEMAND_TRANSFER | DMA_WRITE | DMA_INCREMENT_COUNTER)
volatile int Transfers = 0;
volatile Error = 0, Busy = 0;
volatile int i = 0;
unsigned long NumberofBytes;
int far * DMAPtr1;
int far * DMAPtr2;
unsigned int DMAPage[2], DMAPageOffset[2];
/****************************************************************************
NewISR()
The NewISR function is called whenever an interrupt is generated on the
specified IRQ. It simply checks the busy flag to see if the last transfer
was completed, swaps the buffers to transfer to disk, increments the
"Transfers" variable and clears the DMA done flag.
Do not try to access any functions that use DOS calls (disk access, screen
writes, read keyboard, etc) and do not use floating point operations in
this function. DOS and the Floating Point Emulator are not reentrant and
will cause unexpected happenings if used inside an interrupt.
Before exiting the function passes the End of Interrupt (EOI) command
to the 8259 interrupt controller. Don't forget the EOI command; it is
required even if your ISR does nothing.
****************************************************************************/
#ifdef __cplusplus
void interrupt NewISR(...) // C++ style interrupt function.
#else
void interrupt NewISR(void) // C style interrupt function.
#endif
{
if (Busy == 1) Error = 1; // Make sure write to disk is done
if (i == 0) // before switching DMA buffer pointer.
i = 1;
else
i = 0;
Transfers++;
ClearADDMADone6430(); // Clear Board DMA done
ClearIRQ16430(); // Clear IRQ on DM6430.
EndOfIT(IRQ_CHANNEL); // VERY IMPORTANT !!! Clear interrupt
}
/***************************************************************************
SetProgramScreen()
The SetProgramScreen() function initializes the screen.
****************************************************************************/
void SetProgramScreen(void)
{
clrscr();
// Print header and footer.
gotoxy(1,1); cprintf(TitleString6430());
gotoxy(50, 1); cprintf("DMA Example");
gotoxy(1, 25); cprintf("Press enter key to start. . . ");
gotoxy(30, 8); cprintf("Transfers =");
} //SetProgramScreen
int main(void){
FILE* DataFile;
unsigned long ClockRate;
int Test;
float Range;
float Slope;
unsigned NumberOfPoints;
unsigned long NumberofBytes;
double Actual_PACER_RATE;
clrscr();
NumberofBytes = (long)(DMA_BUF_SIZE) * 2L;
// Allocating first memory buffer for DMA.
DMAPtr1 = allocdmabuffer(NumberofBytes, ADDMAChannel1, &DMAPage[0], &DMAPageOffset[0]);
if (DMAPtr1 == NULL) {
cprintf("Buffer 1 allocation has failed.");
getch();
return 1;
} //if
_fmemset(DMAPtr1, 0x00, NumberofBytes ); // Set buffer to all 0.
// Allocating second memory buffer for DMA.
DMAPtr2 = allocdmabuffer(NumberofBytes, ADDMAChannel2, &DMAPage[1], &DMAPageOffset[1]);
if (DMAPtr2 == NULL) {
cprintf("Buffer 2 allocation has failed.");
getch();
return 1;
} //if
_fmemset(DMAPtr2, 0x00, NumberofBytes ); // Set buffer to all 0.
SetProgramScreen();
Test = 0;
SetBaseAddress(BASE_ADDRESS); // Set BaseAddress
InitBoard6430(); // Initialize board.
Actual_PACER_RATE = SetPacerClock6430(RATE); // Program the pacer clock.
SetChannelGain6430(CHANNEL, GAIN, SE_DIFF); // Set channel and gain.
SetTriggerRepeat6430(0); // Single Cycle.
SetStartTrigger6430(0); // Start Trigger = Software.
SetStopTrigger6430(0); // Stop Trigger = Software.
SetConversionSelect6430(1); // Conversion = Pacer Clock.
// Set up data file and write header.
ClockRate = Actual_PACER_RATE; // Clock rate.
Range = 20; // A/D input range.
Slope = (20.0/65536.0); // A/D volt per bit.
NumberOfPoints = DMA_BUF_SIZE; // Number of samples in 1 buffer.
DataFile = fopen("DUALDMA.DAT", "wb"); // Open data file.
fwrite(&ClockRate, sizeof(ClockRate), 1, DataFile);
fwrite(&Range, sizeof(Range), 1, DataFile);
fwrite(&Slope, sizeof(Slope), 1, DataFile);
fwrite(&NumberOfPoints, sizeof(NumberOfPoints), 1, DataFile);
DisableDMA(ADDMAChannel1); // Disable DMA channel in CPU.
DisableDMA(ADDMAChannel2); // Disable DMA channel in CPU.
SetADDMA6430(ADDMAChannel1, ADDMAChannel2); // Program the board for dual DMA.
SetDMAController(ADDMAChannel1, MODE_REGISTER, DMAPage[0], DMAPageOffset[0], NumberofBytes); // Set DMA Controller.
SetDMAController(ADDMAChannel2, MODE_REGISTER, DMAPage[1], DMAPageOffset[1], NumberofBytes); // Set DMA Controller.
SetIRQ16430(5, IRQ_CHANNEL); // Set Board IRQ1 Source = DMA Done.
// Set IRQ Channel.
ClearIRQ16430(); // Clear IRQ on DM6430.
InitHostIT(NewISR,IRQ_CHANNEL); // Set the Interrupt Service Routine.
ClearADFIFO6430(); // Clear FIFO.
EnableDMA(ADDMAChannel1); // Enable DMA in CPU.
EnableDMA(ADDMAChannel2); // Enable DMA in CPU.
getch();
gotoxy(1, 25); cprintf("Press enter key to stop. . . ");
StartConversion6430(); // Start the measurement.
while (!kbhit()){
if (Error == 1){ // Check error flag.
cprintf("Buffer Overflow %d",Transfers);
goto exiterror;
}
if (Test != Transfers){ // If interrupted, write to disk.
Busy = 1; // Set busy flag.
if (i==0){
fwrite(DMAPtr2, sizeof(int), NumberOfPoints, DataFile);
}
else{
fwrite(DMAPtr1, sizeof(int), NumberOfPoints, DataFile);
}
Test ++; // Increment "Test" variable.
gotoxy(45,8); cprintf("%d",Transfers);
Busy = 0; // Reset busy flag.
}
}
getch();
exiterror:
gotoxy(1, 25); cprintf("Press enter key to graph. . . ");
DisableDMA(ADDMAChannel1); // Disable DMA channel in CPU.
DisableDMA(ADDMAChannel2); // Disable DMA channel in CPU.
ClearADDMADone6430(); // Clear DMA done flag on board.
RestoreHostIT(IRQ_CHANNEL); // Restores the IT vector and disable.
SetIRQ16430(0,0); // Disable board IRQ.
fclose(DataFile); // Close Data file.
freedmabuffer(DMAPtr1); // free DMA Buffer 1.
freedmabuffer(DMAPtr2); // free DMA Buffer 2.
getch();
vgraph("DUALDMA.DAT"); // Graph data.
clrscr(); // Clear screen.
return 0;
} //main
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -