Driver Development Kit (DDK)

cancel
Showing results for 
Search instead for 
Did you mean: 

Linux PCI6071E driver

I've inherited a PCI6071E register-level driver written for and used with RTX/Windows that I'm porting to Linux and I'm having problems getting it to work. I have other NI boards in the system, 5627's and 6703's and they work fine.

 

I want to sample 7 differential channels at 200 Hz. The software that accesses the board wakes up up at 400 Hz, reads the AI_Status_1_Register (base address + 4) and checks for ADC_FIFO_EMPTY (0x1000), returns if it is empty or reads until it's empty. If more than 7 samples are read, it is considered an overflow and the ADC_FIFO is cleared. This all works well running under RTX/Windows.

 

I'm using the open source pciutils routines for accessing and mapping the pci registers into user space.

 

The first problem I saw was when writing to the window register. The program writes the register address to base+0 and then the data to be written to that register to base+2. I added a print statement to print out the value of base+0 and it would always be zero regardless of what I had written to it. I have had trouble during this port with two other boards (non-NI) where I had to add delays at various points when writing to board registers to allow the changes to be affected. I tried adding a short wait after writing to the window registers but it didn't help, so I removed it. I swapped the non-working board from the Linux box with a known working board from an RTX box and after that I could read back what I had written to base+0. (But... the board that was removed from the linux box worked fine in the RTX box).

 

The next problem I found was that the ADC_FIFO_EMPTY bit in the AI_Status_1_Register was never set. The statement was written like this:

 

#define AI_STATUS_REG     (unsigned short*)(m_adcBase+0x04)

#define ADC_FIFO_EMPTY   0x1000 

 

if (*(AI_STATUS_REG) & ADC_FIFO_EMPTY)

   do A

else

   do B

 

The program would always do B, so I slowed the scan rate down to 10 Hz and the poll rate down to 20 Hz and changed to this so I could see what the status register contained:

 

int temp = *(AI_STATUS_REG)

print temp

if (temp & ADC_FIFO_EMPTY)

   do A

else

   do B

 

After this the ADC_FIFO_EMPTY bit was set every other time it was polled (as expected). I removed the print statement and the ADC_FIFO_BIT was again never set. I changed the print to a 1 microsecond sleep and the ADC_FIFO_EMPTY bit was again set every other time. I changed the print to a sched_yield() and it still worked as expected. From this it appears that although the assigment statement returned which would indicate the the read from the board was complete, something hadn't finished. I set the polling rate back to 400Hz annd the scan rate back to 200Hz and got good conversions from the analog channels.

 

The problem I now have is that sometimes the board will work as expected, returning good conversions from the 7 ADC channels, but occasionally, it will get into a mode where the voltages appear in random orders. I set the system up with input voltages of ch0=1.0v, ch1=2.0v, .. ch06 = 7.0v. When polling, the ADC_FIFO_EMPY bit is set one poll and then there are exactly 7 conversions available on the next poll but the voltage to channel order appears to be random, ch0 will be 1v one poll, 4v the next poll, 2v the next. I've tried cycling power (thinking possibly the board setup sequence isn't completely re-initialzing the board) with no help. Twice I've been able to restore correct operation by selecting a very slow scan rate (10 HZ) on the board and then re-initializing the board with the desired 200 Hz scan rate.

 

I've compared the sequence of setup instructions with examples in the E-Series DDK examples and there are a few differences but changes I've made trying to make the program match the examples haven't helped.

 

I tried posting the sequnce of setup instructions but exceed the max char's so I'll reply to this post and add that.

 

Any help would be greatly apprecaited. I've been wrestling with this for several days and now I'm trying to track down a PCI analyzer hoping I can see what the differences are between the RTX and Linux boxes.

0 Kudos
Message 1 of 4
(7,638 Views)

This is the current sequence of setup instructions that are done


#define STROBE_0_REG (unsigned short)(m_adcBase + 0x52)
#define STROBE_1_REG (unsigned short)(m_adcBase + 0x53)
#define CFG_MEMLO      (unsigned short)(m_adcBase + 0x10)
#define CFG_MEMHI       (unsigned short)(m_adcBase + 0x12)

*(STROBE_0_REG) = 0x0001
*(STROBE_1_REG) = 0x0001

#(CFG_MEMHI) = 0x1000
#(CFG_MEMLO) = 0x0000

#(CFG_MEMHI) = 0x1001
#(CFG_MEMLO) = 0x0000

#(CFG_MEMHI) = 0x1002
#(CFG_MEMLO) = 0x0000

#(CFG_MEMHI) = 0x1003
#(CFG_MEMLO) = 0x0000

#(CFG_MEMHI) = 0x1004
#(CFG_MEMLO) = 0x0000

#(CFG_MEMHI) = 0x1005
#(CFG_MEMLO) = 0x0000

#(CFG_MEMHI) = 0x1006
#(CFG_MEMLO) = 0x8000

then these window register writes follow
offset         value
0x0038,56d     0x1b00
0x0008,8d      0x0001
0x0048,72d     0x0001
0x0048,72d     0x0010
0x0002,2d      0x3f80
0x0008,8d      0x0000
0x000c,12d     0x000c
0x0048,72d     0x0100
0x0048,72d     0x0010
0x0038,56d     0x1b80
0x004d,77d     0xa4a0
0x003c,60d     0x032e
0x0048,72d     0x0100
0x0048,72d     0x0010
0x000d,13d     0x0000
0x003c,60d     0x032e
0x0048,72d     0x0100
0x0048,72d     0x0010
0x000c,12d     0x000d
0x003f,63d     0x0060
0x0048,72d     0x0100
0x0048,72d     0x0010
0x000c,12d     0x000e
0x0008,8d      0x0020
0x0048,72d     0x0100
0x0048,72d     0x0010
0x003e,62d     0x0060
0x000e,14d     0x0000
0x000f,15d     0x0001
0x0008,8d      0x0200
0x000e,14d     0x0006
0x000f,15d     0x1a7f
0x0048,72d     0x0100
0x0048,72d     0x0010
0x003e,62d     0x29e0
0x0048,72d     0x0100
0x0048,72d     0x0010
0x0017,23d     0x00c7
0x0019,25d     0x00c7
0x000d,13d     0x0100
0x0008,8d      0x0800
0x000d,13d     0x0300
0x0048,72d     0x0100
0x0053,83d     0x0001
0x0008,8d      0x1540
0x0004,4d      0x0001
0x000b,11d     0x0000

0 Kudos
Message 2 of 4
(7,637 Views)
Hi and welcome to the DDK forum 🙂 It's never fun to inherit someone else's code.

Regarding the reading-the-register ghost of bits past, it sounds like the OS was doing some caching behind your back. Linux does device I/O in bursts, often keeping a local soft copy and re-ordering addresses before sending/receiving it to/from the bus. Sometimes the compiler is the villain, and it can write machine code to cache/reorder instructions. The kernel offers a lot of help when writing/reading registers (memory barriers and disabling hardware caching) [1], but I'm not familiar enough with pciutils to know if any routines in the package can do similar things.

The randomized channel swapping that you're seeing is difficult to troubleshoot with just the raw address/value pairs. Can you translate them to register names, or post code, or recreate the problem using aiex2.cpp from the examples?

[1] Linux Device Drivers, Chapter 9: I/O Ports and I/O Memory
http://lwn.net/images/pdf/LDD3/ch09.pdf
Joe Friedchicken
NI Configuration Based Software
Get with your fellow OS users
[ Linux ] [ macOS ]
Principal Software Engineer :: Configuration Based Software
Senior Software Engineer :: Multifunction Instruments Applications Group (until May 2018)
Software Engineer :: Measurements RLP Group (until Mar 2014)
Applications Engineer :: High Speed Product Group (until Sep 2008)
0 Kudos
Message 3 of 4
(7,614 Views)

The linux comedi drivers support the 6071.  I found those reasonably helpfull untill I discovered NI had the DDK.  If you're interested in using them as a refrence, the relevent code is mostly in the drivers folder: ni_mio_common.*, ni_pcimio.*, ni_stc.*, and mite.*.

0 Kudos
Message 4 of 4
(6,886 Views)