DMA programming question

Hello World :slight_smile:

There are no instructions about finding PAGE and OFFSET of data buffer in
QNX RTP 6.1 documentation. I try to program DMA registers. Another questions
are if I have to map data buffer using mmap() or similar system function and
if I have map IO device for using in8() and out8() with DMA?

Darek Borkowski

Hi Darek,

I’m sorry: what do you need PAGE and OFFSET for? It is usual things for 16-bit programming. Page
and offset registers in DMA make a different sense.
Load page reg = address>>16 (bits 23-17) and offset reg = (address&0x0FFFF)>>1 for 16-bit DMA
transfers. For 8-bit DMA transfers offset is lower 16 address bits without shifting.
I suggest you are using standard PC/AT DMA controller. I have no expirience with QNX, but it works
with ISA cards under different OS.

Good luck,
Eduard.

Darek Borkowski <borkows@uci.agh.edu.pl> wrote in article <9mfiml$nc9$1@inn.qnx.com>…

Hello World > :slight_smile:

There are no instructions about finding PAGE and OFFSET of data buffer in
QNX RTP 6.1 documentation. I try to program DMA registers. Another questions
are if I have to map data buffer using mmap() or similar system function and
if I have map IO device for using in8() and out8() with DMA?

Darek Borkowski
\

BIGG thanks!
Do you know something about addresses of DMA registers. I’m not sure if DMA
registers lay bettween 0x00 and 0xD8. Its very low addresses. Are they ok?

Darek

Hi Darek,

I’m sorry: what do you need PAGE and OFFSET for? It is usual things for
16-bit programming. Page
and offset registers in DMA make a different sense.
Load page reg = address>>16 (bits 23-17) and offset reg =
(address&0x0FFFF)>>1 for 16-bit DMA
transfers. For 8-bit DMA transfers offset is lower 16 address bits
without shifting.
I suggest you are using standard PC/AT DMA controller. I have no
expirience with QNX, but it works
with ISA cards under different OS.

Good luck,
Eduard.

Darek Borkowski <> borkows@uci.agh.edu.pl> > wrote in article
9mfiml$nc9$> 1@inn.qnx.com> >…
Hello World > :slight_smile:

There are no instructions about finding PAGE and OFFSET of data buffer
in
QNX RTP 6.1 documentation. I try to program DMA registers. Another
questions
are if I have to map data buffer using mmap() or similar system function
and
if I have map IO device for using in8() and out8() with DMA?

Darek Borkowski
\

You’re probably talking about PCI config space registers. Each PCI
device has 256-byte long config space with 64-byte header (afair)
followed by hardware-specific registers. The 0x00 - 0xD8 must be offsets
of those registers.

  • igor

Darek Borkowski wrote:

BIGG thanks!
Do you know something about addresses of DMA registers. I’m not sure if DMA
registers lay bettween 0x00 and 0xD8. Its very low addresses. Are they ok?

Darek

Hi Darek,

I’m sorry: what do you need PAGE and OFFSET for? It is usual things for
16-bit programming. Page
and offset registers in DMA make a different sense.
Load page reg = address>>16 (bits 23-17) and offset reg =
(address&0x0FFFF)>>1 for 16-bit DMA
transfers. For 8-bit DMA transfers offset is lower 16 address bits
without shifting.
I suggest you are using standard PC/AT DMA controller. I have no
expirience with QNX, but it works
with ISA cards under different OS.

Good luck,
Eduard.

Darek Borkowski <> borkows@uci.agh.edu.pl> > wrote in article
9mfiml$nc9$> 1@inn.qnx.com> >…
Hello World > :slight_smile:

There are no instructions about finding PAGE and OFFSET of data buffer
in
QNX RTP 6.1 documentation. I try to program DMA registers. Another
questions
are if I have to map data buffer using mmap() or similar system function
and
if I have map IO device for using in8() and out8() with DMA?

Darek Borkowski
\

No, I think he’s referring to the 8237, which has registers mapped
between 00 and 1F (DMA 0-3) and C0 and DF (DMA 4-7) on the PC
architecture. Not sure why the question is being asked here though,
there is a ton of docs on the web about programming PC DMA. I think
the question aimed at this forum is how to get physical addresses, which
is a FAQ/RTFM (see mem_offset/posix_mem_offset).

-----Original Message-----
From: Igor Kovalenko [mailto:Igor.Kovalenko@motorola.com]
Posted At: Tuesday, August 28, 2001 12:57 PM
Posted To: applications
Conversation: DMA programming question
Subject: Re: DMA programming question


You’re probably talking about PCI config space registers. Each PCI
device has 256-byte long config space with 64-byte header (afair)
followed by hardware-specific registers. The 0x00 - 0xD8 must be offsets
of those registers.

  • igor

Darek Borkowski wrote:

BIGG thanks!
Do you know something about addresses of DMA registers. I’m not sure
if DMA
registers lay bettween 0x00 and 0xD8. Its very low addresses. Are they
ok?

Darek

Hi Darek,

I’m sorry: what do you need PAGE and OFFSET for? It is usual things
for
16-bit programming. Page
and offset registers in DMA make a different sense.
Load page reg = address>>16 (bits 23-17) and offset reg =
(address&0x0FFFF)>>1 for 16-bit DMA
transfers. For 8-bit DMA transfers offset is lower 16 address bits
without shifting.
I suggest you are using standard PC/AT DMA controller. I have no
expirience with QNX, but it works
with ISA cards under different OS.

Good luck,
Eduard.

Darek Borkowski <> borkows@uci.agh.edu.pl> > wrote in article
9mfiml$nc9$> 1@inn.qnx.com> >…
Hello World > :slight_smile:

There are no instructions about finding PAGE and OFFSET of data
buffer
in
QNX RTP 6.1 documentation. I try to program DMA registers. Another
questions
are if I have to map data buffer using mmap() or similar system
function
and
if I have map IO device for using in8() and out8() with DMA?

Darek Borkowski
\

Rennie Allen <RAllen@csical.com> wrote in article
<64F00D816A85D51198390050046F80C9A322@exchangecal.hq.csical.com>…

No, I think he’s referring to the 8237, which has registers mapped
between 00 and 1F (DMA 0-3) and C0 and DF (DMA 4-7) on the PC
architecture. Not sure why the question is being asked here though,
there is a ton of docs on the web about programming PC DMA. I think
the question aimed at this forum is how to get physical addresses, which
is a FAQ/RTFM (see mem_offset/posix_mem_offset).

I’m sure Darek is refering to the 8237 DMA controller registers.
0x00 - 0x07 base addr and offset ch0-ch3
0x08 - 0x0f DMA control/status
0x81 - 0x8f DMA page registers
0xc0 -0xcf base addr and offset ch4-ch7
0xd0 - 0xdf DMA control/status
All are 16-bits registers: read/write low byte, then the high byte at the same i/o port.
8237 operates with physical address, so page and base/current (offset) address registers keep
physical address. Memory allocation functions get for you physical address in QNX and they take
care about boundaries and so on.

Good luck!
Eduard.

ed1k <ed1k@yahoo.com> wrote in article 01c1305f$20b14780$396fa8c0@ED1K
[snip]

Memory allocation functions get for you physical address in QNX and they take
care about boundaries and so on.
Darek,

I’m sorry… My fault.
mmap() takes care aboud boundaries and so on,
mem_offset() gets for you physical address.

Good luck!
Eduard.

Yes, I’m refering to 8237. I’m trying to write driver for data acquisition
card Advantech PCL 818L (its ISA card for plain PC).
Thanks for all!

Darek


U¿ytkownik “ed1k” <ed1k@yahoo.com> napisa³ w wiadomo¶ci
news:01c13087$398acb00$396fa8c0@ED1K…

ed1k <> ed1k@yahoo.com> > wrote in article
01c1305f$20b14780$396fa8c0@ED1K>…
[snip]
Memory allocation functions get for you physical address in QNX and they
take
care about boundaries and so on.
Darek,
I’m sorry… My fault.
mmap() takes care aboud boundaries and so on,
mem_offset() gets for you physical address.


Good luck!
Eduard.

Hi Eduard!
I am near to success with DMA. Below is sample of my program. This sample
code works except one importatnt thing.

I use DMA in 8 bit mode with old ISA DAQ card. I programmed DMA to Single
mode with No Autoinitialization. May DAQ card triggrers AD conversion on
each internal Pacer tick. After each Conversion the DAQ card generates two
succesive DMA REQUEST signals (cause it gives two bytes from each AD
conversion). After that DMA has exclusive access to data bus and transfers
two bytes to buffer in memory. Before all I initialize my buffer with 0xAAAA
(1010101010101010). After all transfers (Terminal Count is reached in DMA) I
don’t get any new value in my buffer, there are still 0xAAAA.

I use mem_offset() to get physical address of my buffer maped with mmap(). I
know that physical address is 0x099000.

ADBuffer = (short*) mmap(0, NumberOfADConversions * sizeof(short), PROT_READ
| PROT_WRITE | PROT_NOCACHE, MAP_ANON | MAP_PHYS | MAP_NOX64K |
MAP_BELOW16M, NOFD, 0);

mem_offset((void *) ADBuffer, NOFD, NumberOfADConversions * sizeof(short),
&offset, 0);

I suppose that I write wrong values to DMAPageReg (8bit) and DMAAddrReg
(16bit). I tested it and I have proper value in AddrReg. This value is
incrementing. But I cannot read DMAPageReg, I always get 0x00 from it. Maybe
because DMAPageReg is separate chip (74LSxxxx) outside DMA. I think that my
data is being transferred to unknown area of my memory, not to buffer.
I write 7-0 bits of buffer address to DMAAddrReg, then 15-8 bits of address
to DMAAddrReg, then 23-16 bits DMAPageReg.

Maybe You do know what is the problem.

regards
Darek

======================= SAMPLE OF MY PROGRAM ====================
char DMAChannels[4] = { 0 , 1 , 2 , 3 };
char DMAMaskReg[4] = { 0x0A, 0x0A, 0x0A, 0x0A};
char DMAModeReg[4] = { 0x0B, 0x0B, 0x0B, 0x0B};
char DMAClearReg[4] = { 0x0C, 0x0C, 0x0C, 0x0C};
char DMAPageReg[4] = { 0x87, 0x83, 0x81, 0x82};
char DMAAddrReg[4] = { 0x00, 0x02, 0x04, 0x06};
char DMACountReg[4] = { 0x01, 0x03, 0x05, 0x07};



dma = 3;

do
{
for(bufno = 0; bufno < 2 ; bufno++)
{
if(pprm → ADStatus & 0x8000) break;
printf(“Before DMA Set…”);

InterruptDisable();
out8(pprm → Port + 9, control & ~0x04);
//clears DMAE bit
out8(DMAMaskReg[dma], 0x04 | dma);
//masks channel no. dma
out8(DMAClearReg[dma], 0x00);
//stops all transfers
out8(DMAModeReg[dma], 0x50 | 0x04 | (dma & 0x03));
//sets Single mode of DMA operation
out8(DMAAddrReg[dma], offset & 0x000000FF); //writes
7 - 0 bits of phys address
out8(DMAAddrReg[dma], (offset & 0x0000FF00) >> :sunglasses:; //writes
15 - 8 bits of phys address
out8(DMAPageReg[dma], (offset & 0x00FF0000) >> 16); //writes
23 - 16 bits of phys address
out8(DMACountReg[dma], transfers & 0x00FF);
//sets number of transfers (bytes in buffer)
out8(DMACountReg[dma], (transfers & 0xFF00) >> :sunglasses:;
out8(DMAMaskReg[dma], 0x03 & dma);
//clears the mask from channel no. dma
out8(pprm → Port + 9, control | 0x04);
//sets DMAE bit
InterruptEnable();

printf(“DMA Set…\n”);
InterruptWait(NULL, NULL);
out8(pprm → Port + 8, 0x00); //clear INT bit
InterruptUnmask(InterruptLevel, isr_handler_id);

printf(“After an INTERRUPT\n”);
pthread_mutex_lock(&mutex);
ReadyADBuffer = ADBuffer;
ADWriteCount++;
pthread_mutex_unlock(&mutex);
}
} while(CyclicMode && !(ADStatus & 0x8000));

Hi Darek,
Would be better to ask this question by e-mail. Unfortunately I have no my source at the moment.
I’ll look at my program at home. As far as I can remember all registers need to be written twice,
I’m not sure, but try
out8(DMAPageReg[dma], (offset & 0x00FF0000) >> 16);
out8(DMAPageReg[dma], 0);
Or wait for tomorrow.

Best regards,
Eduard.

Hi Darek,

Forget all I’ve said yesterday, try the following code:

char DMAChannels[4] = { 0 , 1 , 2 , 3 };
char DMAMaskReg[4] = { 0x0A, 0x0A, 0x0A, 0x0A};
char DMAModeReg[4] = { 0x0B, 0x0B, 0x0B, 0x0B};
char DMAClearReg[4] = { 0x0C, 0x0C, 0x0C, 0x0C};
char DMAPageReg[4] = { 0x87, 0x83, 0x81, 0x82};
char DMAAddrReg[4] = { 0x00, 0x02, 0x04, 0x06};
char DMACountReg[4] = { 0x01, 0x03, 0x05, 0x07};
char DMARequestReg[4] = { 0x09, 0x09, 0x09, 0x09};


dma = 3;

//================== DMA Setup Section ====================

//mask DMA channel while programming
out8(DMAMaskReg[dma], 0x04 | dma);

//reset DMA request register
out8(DMARequestReg[dma], 0x03 & dma);

//clear the flip-flop
out8(DMAClearReg[dma], 0x00);

//set DMA mode: single request mode, disable auto-initialization,
// write to memory, address increment
out8(DMAModeReg[dma], 0x40 | 0x04 | (dma & 0x03));
/* are you sure you wish to enable auto-initialization? */

//write page (23 - 16 bits of phys address)
out8(DMAPageReg[dma], (offset & 0x00FF0000) >> 16);

//write address (15 - 0 bits of phys address)
out8(DMAAddrReg[dma], offset & 0x000000FF); //lo
out8(DMAAddrReg[dma], (offset & 0x0000FF00) >> :sunglasses:; //hi

//sets number of transfers (bytes in buffer)
out8(DMACountReg[dma], transfers-1 & 0x00FF); //lo
out8(DMACountReg[dma], (transfers-1 & 0xFF00) >> :sunglasses:; //hi
/* transfers==buffer_lenght? then minus 1 ^^ is required, *

  • DMA transfer ends when this counter==0xFFFF */

//unmask DMA channel
out8(DMAMaskReg[dma], 0x03 & dma);

//================== End DMA Setup ====================

Hope this helps.
Good luck,
Eduard.