11-16-2009 12:30 PM
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.
11-16-2009 12:31 PM
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
11-17-2009 10:24 AM
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)
07-14-2010 05:07 PM
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.*.