Blame |
Last modification |
View Log
| RSS feed
/*****************************************************************************
* Filename: pci6025e.c *
* Author: Ziglioli Marco *
* Date: 15/03/2001 *
* Description: Collection of routines to find on PCI bus and configure Natio-*
* nal Instruments PCI6025E multifunction board. This board has *
* - One ADC 12 bit flash with 16 input lines (multiplexed) *
* - Two DACs 12 bit *
* - Eight Digital lines drived through NI DAQ-STC IC *
* - Twentyfour Digital lines drived through OKI MSM82C55A *
* - Two General purpose 24-bit counters/timers *
* - Timing module for analog input (AITM) *
* - Timing module for analog output (AOTM) *
* - 10 Programmable Function pins (PFI) *
* - RTSI bus for connection with other National Board *
* - Timing module which can provide frequency from 20MHz to *
* 6,25 KHz *
* - Two shared interrupt groups to manage up than 20 different *
* interrupt events *
* For more information please refer to National Web site: www.ni.com *
*----------------------------------------------------------------------------*
* Notes: Based on National C Routines *
*****************************************************************************/
/* This file is part of the S.Ha.R.K. Project - http://shark.sssup.it
*
* Copyright (C) 2001 Marco Ziglioli
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <drivers/pci6025e/pci6025e.h>
//Software copy of importan register
static WORD interrupt_control;
// PJ: Global data
struct pci6025e_deviceinfo NIDevice_info[10];
DWORD *IntLinestructptr;
DWORD *BAR0structptr;
DWORD *RevID;
DWORD STC_Base_Address, MITE_Base_Address;
//Software copy of STC general registers
WORD joint_reset, interrupt_a_enable, interrupt_a_ack,
interrupt_b_enable, interrupt_b_ack, clock_and_fout;
/*****************************************************************************
* Usefull(???) Functions *
*****************************************************************************/
/*****************************************************************************
* Print value of each bit contained in value *
*****************************************************************************/
void bitfield(BYTE dim, DWORD value)
{
int i;
for(i=(dim*8)-1; i>=0; i--)
cprintf("%ld",(value>>i)%2);
cprintf("\n");
}
/*****************************************************************************
* Print custom string (str) before printing the bitfield *
*****************************************************************************/
void TEST_bitfield(BYTE dim, DWORD value, char *str)
{
cprintf("%s", str);
bitfield(dim, value);
}
/*****************************************************************************
* Low Level Functions to write in windowed mode into DAQ STC *
*****************************************************************************/
void DAQ_STC_Windowed_Mode_Write(WORD addr, WORD Value)
{
kern_cli();
*((WORD *)(STC_Base_Address + WIN_ADDR_REG)) = addr;
*((WORD *)(STC_Base_Address + WIN_DATA_WR_REG)) = Value;
kern_sti();
}
WORD DAQ_STC_Windowed_Mode_Read(WORD addr)
{
WORD value = 0;
kern_cli();
*((WORD *)(STC_Base_Address + WIN_ADDR_REG)) = addr;
value = *((WORD *)(STC_Base_Address + WIN_DATA_RD_REG));
kern_sti();
return (value);
}
/*****************************************************************************
* Detect all NI Devices on PCI bus *
*****************************************************************************/
BYTE find_NI_Device(void)
{
WORD devNumFunNum = 0;
WORD busNum, i = 0;
DWORD value, temp, Device_ID;
BYTE hdr, Device_Count;
int present;
Device_Count = 0;
BAR0structptr = &NIDevice_info[0].BAR0Value;
IntLinestructptr = &NIDevice_info[0].IntLineRegValue;
RevID = &NIDevice_info[0].RevisionID;
for(busNum = 0; busNum <= 0; busNum++){
for(devNumFunNum = 0; devNumFunNum <= 0xFF; devNumFunNum += 0x08){
present = 0;
if((devNumFunNum & 0x07) == 0){
present = pcibios_read_config_byte((BYTE)busNum,
(BYTE)devNumFunNum, 0x0E, &hdr);
if(hdr & 0x80)
present = 1;
if(present){
if(pcibios_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum,
0x00, &value) && (value != 0xffffffff)){
if((value & 0xffffL) == NI_CODE){
Device_ID = value;
Device_ID &= 0xFFFF0000;
Device_ID = Device_ID >> 16;
NIDevice_info[i].DEVID = (WORD)temp;
NIDevice_info[i].DevFunction = (BYTE)devNumFunNum;
NIDevice_info[i].BusNumber = (BYTE)busNum;
pcibios_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, 0x10, (DWORD *)BAR0structptr);
pcibios_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, 0x3C, (DWORD *)IntLinestructptr);
pcibios_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, 0x08, (DWORD *)RevID);
NIDevice_info[i].InterruptLevel = (BYTE)NIDevice_info[i].IntLineRegValue;
i++;
BAR0structptr++;
IntLinestructptr++;
RevID++;
Device_Count++;
}
}
}
}
}
}
return Device_Count;
}
/*****************************************************************************
* Remap Base address of STC and MITE registers presents on NI boards *
* Note: If there's over than one NI Board on bus only the first device is *
* remapped *
*****************************************************************************/
BYTE reMap(void)
{
//DWORD Mite_Data;
//DWORD Value;
if(!find_NI_Device()){
return 0;
}
/*
// ***************************************************************
// This is usefull to remap board in another memory zone
// Enable this and choose memory zone setting BAR0 and BAR1 values
// on PCI6025E.H
// ***************************************************************
// Set Up MITE
Value = BAR0;
pcibios_write_config_dword((BYTE)NIDevice_info[0].BusNumber,
NIDevice_info[0].DevFunction, 0x10, Value);
Mite_Data = 0xAEAE;
lmempoked(BAR0 + 0x0340, Mite_Data);
// Set Up Board
Value = BAR1;
pcibios_write_config_dword((BYTE)NIDevice_info[0].BusNumber,
NIDevice_info[0].DevFunction, 0x14, Value);
Mite_Data = (BAR1 & 0xFFFFFF00) | 0x80;
lmempoked(BAR0 + 0xC0, Mite_Data);
*/
//Setting up Base Address
pcibios_read_config_dword((BYTE)NIDevice_info[0].BusNumber,
(BYTE)NIDevice_info[0].DevFunction, 0x14, &STC_Base_Address);
STC_Base_Address = (STC_Base_Address & 0xFFFFFF00) | 0x80;
pcibios_read_config_dword((BYTE)NIDevice_info[0].BusNumber,
(BYTE)NIDevice_info[0].DevFunction, 0x10, &MITE_Base_Address);
//MITE_Base_Address &= 0xFFFFFF00;
*((DWORD *)MITE_Base_Address) = 0xAEAE;
*((DWORD *)(MITE_Base_Address + 0xC0)) = STC_Base_Address;
return 1;
}
/*****************************************************************************
* Sets up the internal timebase clock and enable Frequency Out (FOUT). *
* Signal is available on pin 50 *
*----------------------------------------------------------------------------*
* tbs -> if 0 then 20 Mhz freq; if 1 then 200 Khz freq *
* divBy2 -> if 1 divides output frequency by two else if 0 doesn't *
* divide it *
* divider -> if 0 divides frequency by 16 *
* if between 1 and 15 divides frequency by specified value *
*****************************************************************************/
BYTE setIntClock(BYTE tbs, BYTE divBy2, BYTE divider)
{
clr(clock_and_fout, 15);
DAQ_STC_Windowed_Mode_Write(CLOCK_AND_FOUT, clock_and_fout);
switch(tbs){
case 0:
clr(clock_and_fout, 14); //IN_TIMEBASE
break;
case 1:
set(clock_and_fout, 11); //Enable IN_TIMEBASE2
set(clock_and_fout, 14); //Select IN_TIMEBASE2
break;
default:
return 0;
break;
}
switch(divBy2){
case 0: clr(clock_and_fout, 12); break; //Not divided by two
case 1: set(clock_and_fout, 12); break; //Divided by two
default: return 0; break;
}
//if((divider < 0) || (divider > 15))
if(divider > 15) // PJ: byte has only positive values!!!
return 0; //Addictional frequency division wrong
if(divider & 0x01)
set(clock_and_fout, 0);
else
clr(clock_and_fout, 0);
if(divider & 0x02)
set(clock_and_fout, 1);
else
clr(clock_and_fout, 1);
if(divider & 0x04)
set(clock_and_fout, 2);
else
clr(clock_and_fout, 2);
if(divider & 0x08)
set(clock_and_fout, 3);
else
clr(clock_and_fout, 3);
//Write in register
DAQ_STC_Windowed_Mode_Write(CLOCK_AND_FOUT, clock_and_fout);
//Enable internal clock
set(clock_and_fout, 15);
DAQ_STC_Windowed_Mode_Write(CLOCK_AND_FOUT, clock_and_fout);
return 1;
}
/*****************************************************************************
* void PFIprogramming(WORD pfi) *
*----------------------------------------------------------------------------*
* Use this function to program the direction of the ten available PFI lines *
* Parameter: pfi bit 0 through 9: 0 releted PFI line configured as input *
* 1 releted PFI line configured as output*
* 10..15 NOT USED *
*****************************************************************************/
void PFIprogramming(WORD pfi)
{
DAQ_STC_Windowed_Mode_Write(IO_BIDIRECTION_PIN, (pfi & 0x03FF));
}
/*****************************************************************************
* Interrupt manage module *
*****************************************************************************/
/*****************************************************************************
* void INT_personalize(BYTE personal) *
*----------------------------------------------------------------------------*
* Use this function to select the logic level will indicate an interrupt *
* condition on IRQ_OUT pins and to enable or disable the possibility of *
* duplicate selected interrupt to IRQ_OUT<0..1> pins *
* Parameter: personal: bit 0: enable(1) or disable(0) signal duplication *
* bit 1: polarity: (0)active high (1)active low *
* bit 2..7 NOT USED *
*****************************************************************************/
void INT_personalize(BYTE personal)
{
if( (personal & 0x02) ) set(interrupt_control, 0);
else clr(interrupt_control, 0);
if( (personal & 0x01) ) set(interrupt_control, 1);
else clr(interrupt_control, 1);
DAQ_STC_Windowed_Mode_Write(INTERRUPT_CONTROL, interrupt_control);
}
/*****************************************************************************
* void INT_setup(BYTE ga, BYTE gb) *
*----------------------------------------------------------------------------*
* Use this function to enable interrupt groups and to indicate which pin *
* indicate interrupt condition. *
* Parameter: ga: group A manages AITM, IRQ_IN0, Counter0 *
* gb: group B manages AOTM, IRQ_IN1, Counter1 *
* Both parameters have first 3 bits (0..2) to indicate IRQ_OUT pin that will *
* indicate interrupt condition and the fourth bit (3) to enable the *
* interrupts group. *
* Upper 4 bits of each BYTE are NOT USED *
*****************************************************************************/
void INT_setup(BYTE ga, BYTE gb)
{
if( (ga & 0x08) )
interrupt_control = (interrupt_control & 0xF0FF) |
((ga & 0x0F) << 8);
else
clr(interrupt_control, 11);
if( (gb & 0x08) )
interrupt_control = (interrupt_control & 0x0FFF) |
((gb & 0x0F) << 12);
else
clr(interrupt_control, 15);
DAQ_STC_Windowed_Mode_Write(INTERRUPT_CONTROL, interrupt_control);
}
/*End of file: pci6025e.c*/