QuickAudine
USB interface for the Audine CCD camera
Update: 26/01/2003
QuickAudine comes in the form of a small casing
and is used to connect the Audine camera to a computer fitted with a USB interface
(Universal Serial Bus). It is NOT necessary to modify the camera. Even for non-experts,
the installation is very easy due to the Plug&Play characteristic of the
USB interface.
Compared to the initial parallel interface of the Audine, QuickAudine has the following advantages:
The QuickAudine interface in action. It is placed in a little casing that you see here connected to the camera by a short parallel cable. The initial parallel cable of the Audine camera can be used for that purpose. On the other side of the casing, the USB cable goes to the computer.
QuickAudine is available in two ways:
QuickAudine was designed by Thierry
Maciaszek, with the collaboration of the members of the group Pixels & Cassoulet.
Short Description
The heart of the interface is an FT245 circuit (FTDI Chip). A 16F876 PIC microcontroller at 20 MHz supplements the system. This microcontroller emulates the operation of the printer port and implements the reading code of the Audine camera. The code of the 16F876 is written in FlashBasic.
Programming examples of the FT245 chip can be found on the FTDI site. One of the main interests of these chips is that its manufacturer puts their drivers at your disposal free and free of rights. The reliability of this code seems excellent.
A simple communication protocol between QuickAudine and the PC was written. Once these parameters are loaded in the memory of the PIC controller (image format , binning, etc), the command is returned to the PC to count the integration time. It is then the PIC code which takes over to read the CCD, pixel after pixel, and to transmit digital information towards the PC. The interface is compatible not only with the Audine series, but also with its many clones and in particular the Genesis camera produced in the USA.
You will find at the end of this page a programming example of the interface board through a specially written DLL (this DLL is used for example by the Pisco program to manage Audine).
The printed circuit board is carrying the FT245 chip (small square at the top) and the 16F876 controller mounted on a socket. Two LEDs make it possible to check the operation of the system.
Installating QuickAudine
When first connecting the interface to the computer, the operating system immediately detects a new peripheral equipment. At this stage, you must provide the driver of the interface. It can be freely downloaded from the FTDI site . You can also get a version by clicking here (unzip the ZIP file "DRIVERS.ZIP" of 50K and copy the files extracted to a diskette or a CDROM for example).
When first connecting QuickAudine, this is the dialog box you will see on screen (Windows XP system):
Choose the option "Install from a specified location" and click on the "Next" button. A new dialog box appears:
Click on "Next". After a while, you will be asked for the location of the interface driver:
Give the path of the floppy, the CDROM, or the folder where you copied the driver installation files.
A warning message is displayed on the screen. Dont panic (!) and click on "Continue".
After a few seconds, Windows tells you that the installation is completed. The green indicator of the interface is lit. You can now use QuickAudine! You see, this is fairly easy.
Using Pisco with the QuickAudine interface
You must have Pisco version 2.0.
To download Pisco V2.0, click here. Before installing version 2.0, it is recommended to uninstall any previous version.
Run Pisco V2.0 and to go to the "Settings" tab , then click on the "Advanced Settings" button . The following dialog box appears:
Choose the "USB Interface" option. Also choose to switch off the amplifier during the exposure, which is always recommended.
Click on "OK".
In the "Settings" tab, if your Audine camera is fitted with an shutter, you may want to define the time given to the shutter to close before the image is read. You can use a delay of up to 2.4 seconds with QuickAudine.
You can now acquire your first image.
When the image is read after the exposure time, the red indicator of the interface comes on deemly. If your computer is slow, or if the USB is busy, the transfer from the camera to the computer might be altered. If so, the red LED becomes intermittlently brighter. This results in deem horizontal lines in the image as shown below:
This image comes from an Audine KAF-1600 and is acquired in binning 2x2. The exposure time is 5 seconds without cooling, which explains the many hot points in the image. Several defective pixels also disturb the reading of the columns (vertical lines). Horinzontal lines are caused by the problem of temporary slowdown in image reading. During this reading, the PC was connected to the network via a DSL moden connected on the USB port, which is not recommended at all for a clean reading of the image! Of course you can remove this USB load but this problem can be easily removed by cooling the camera, as shown in the following image:
Programming example with QUICKA.DLL
By installing Pisco, a DLL with the name QUICKA.DLL is automatically copied in the folder windows/system (under Windows 98) or the folder windows/system32 (under Windows 2000, XP).
You can download this DLL independently of Pisco and use it for your own applications.
Click here to download QUICKA.DLL (file of 30 KB - V1.1).
The C sources of QUICKA.DLL can be downloaded by clicking here (sources.zip file of 15 KB). You will find all you need to carry out a compilation under Visual C++ 6.0. These sources are free of rights and can be freely modified. However, we ask you to share your tips and tricks with the community of Audine and derived camera users through publications (Web sites, articles or others).
Here a source code sample in VisualBasic 6.0 :
------------------------
(1)
Declare QUICKA functions
------------------------
Public
Declare Function usb_loadlib Lib "QUICKA.DLL" () As Integer
Public
Declare Function usb_closelib Lib "QUICKA.DLL" () As Integer
Public
Declare Function usb_init Lib "QUICKA.DLL" () As Integer
Public
Declare Function usb_end Lib "QUICKA.DLL" () As Integer
Public
Declare Function usb_write Lib "QUICKA.DLL" (ByVal v As Integer) As
Integer
Public Declare Function usb_start Lib "QUICKA.DLL" (ByVal
KAF As Integer, _
ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer,
ByVal y2 As Integer, _
ByVal bin_x As Integer, ByVal bin_y As Integer, ByVal
shutter As Integer, _
ByVal shutter_mode As Integer, ByVal ampli_mode As
Integer, ByVal acq_mode As Integer, _
ByVal d1 As Integer, ByVal d2 As Integer,
ByRef imax As Integer, _
ByRef jmax As Integer) As Integer
Public Declare
Function usb_readaudine Lib "QUICKA.DLL" (ByVal imax As Integer, _
ByVal
jmax As Integer, ByRef buf As Integer) As Integer
-----------------------------
(2)
Some variable declarations...
-----------------------------
Dim shutter As Integer, shutter_mode As
Integer
Dim ampli_mode As Integer, d1 As Integer, d2 As Integer
Dim x1
As Integer, x2 As Integer, y1 As Integer, y2 As Integer
Dim bin_x As Integer,
bin_y As Integer
Dim KAF As Integer, program as Integer, r As Integer
Dim
speed As Integer
Dim
imax As Integer, jmax As Integer
Dim delay As Double
------------------------------
(3)
Load the USB library functions
------------------------------
r = usb_loadlib() ' Register the FTDI USB
functions
If r <> 0 Then
MsgBox ("ERROR:
QuickAudine USB interface driver not found")
Exit
Sub
End If
r = usb_init() ' Check physical presence
of QuickAudine interface
If r <> 0 Then
MsgBox
("ERROR: QuickAudine USB interface not connected")
Exit
Sub
End If
r = usb_end() ' End of the check
------------------------------------------------------------------
(4)
Configuration of the acquisition, clear the CCD and start exposure
------------------------------------------------------------------
shutter = 1 ' Synchro shutter (0 value
= close shutter)
shutter_mode = 0 ' Inversion of the shutter command (1 value
= inverted mode)
ampli_mode = 1 ' shutdown the CCD amplifier during exposure
(0 value = always on)
delay = 1.2 ' delay in seconds between shutter close
and effective reading of the images
If delay > 2.4 Then ' 2.4 seconds
is the max. value
d1 = 0
d2 = 15
Else
d1 = 0
d2 = CInt(6.25 * delay)
End
If
x1 = 1 : y1 = 1 : x2 = 768 : y2 = 512 ' digitized image zone (KAF-0400
full frame example)
bin_x = 1 : bin_y = 1 ' binning factor (valid value:
1, 2, 3 and 4)
KAF = 1 ' CCD model (1 = KAF0400 , 2 = KAF1600)
program
= 1 ' version of the QuickA internal program version
speed = 6 ' speed of
the interface (valid value: 1...15 - standard value=6)
' Setup of the acquisition
' Note:
the usb_start function return the effective size of the image (imax, jmax)
r
= usb_start(KAF, x1, y1, x2, y2, bin_x, bin_y, shutter, shutter_mode, _
ampli_mode,
program, d1, d2, speed, imax, jmax)
If r = 12 Then
MsgBox
("Error: QuickAudine USB interface USB not ready")
Exit
Sub
ElseIf r = 16 Then
MsgBox ("Error: Dialog
problem with the QuickAudine USB interface")
Exit
Sub
ElseIf r = 17 Then
MsgBox ("Error: USB data
transmission error")
Exit Sub
End If
-------------------------------
(5) Gestion of the integration time
-------------------------------
...
... Your code
...
-------------------
(6)
End of the exposure
-------------------
r = usb_write(255) ' CCD amplifier on
Sleep
(100) ' small delay
r = usb_write(255) ' Close the shutter
--------------
(7)
Read the image
--------------
' allocate memory (note: option base 0
for the arrays)
ReDim buffer(imax - 1,jmax - 1) As Integer
r = usb_readaudine(imax, jmax, buffer(0, 0))
' Note: The reading start after the delay (d1, d2) relative to the shutter shutdown
-------------------------------------------
(8)
Erase USB FTDI library functions (optional)
-------------------------------------------
r = usb_closelib()
' The image is now in the 768x512 - 16-bits array BUFFER(i,j)
' It's all !
Direct call of the FTDI functions
Visual C++ program sample for read the Audine camera (direct use of FTDI routines).
//////////// C DRIVER ROUTINES FOR QuickAudine
USB interface ////////////
//
// Some declaration in the header of
your program
typedef DWORD FT_HANDLE;
typedef DWORD FT_STATUS;
EXTERN
FT_HANDLE UsbHandle;
EXTERN HMODULE g_usb_module;
typedef FT_STATUS
(WINAPI *PtrToOpen)(PVOID, FT_HANDLE *);
EXTERN PtrToOpen g_usb_Open;
EXTERN
int UsbOpen(PVOID);
typedef FT_STATUS (WINAPI *PtrToClose)(FT_HANDLE);
EXTERN
PtrToClose g_usb_Close;
EXTERN int UsbClose();
typedef FT_STATUS (WINAPI
*PtrToRead)(FT_HANDLE, LPVOID, DWORD, LPDWORD);
EXTERN PtrToRead g_usb_Read;
EXTERN
int UsbRead(LPVOID, DWORD, LPDWORD);
typedef FT_STATUS (WINAPI *PtrToWrite)(FT_HANDLE,
LPVOID, DWORD, LPDWORD);
EXTERN PtrToWrite g_usb_Write;
EXTERN int UsbWrite(LPVOID,
DWORD, LPDWORD);
typedef FT_STATUS (WINAPI *PtrToResetDevice)(FT_HANDLE);
EXTERN
PtrToResetDevice g_usb_ResetDevice;
EXTERN int UsbResetDevice();
typedef
FT_STATUS (WINAPI *PtrToGetQueueStatus)(FT_HANDLE, LPDWORD);
EXTERN PtrToGetQueueStatus
g_usb_GetQueueStatus;
EXTERN int UsbGetQueueStatus(LPDWORD);
///////////////////////////////////////////////////////
//
First, load FTDI library at the start of the program
///////////////////////////////////////////////////////
open_ftdi();
// At the end of the program call to the routine close_libftdi()
/////////////////////////////////
//
Main routine for read an image
/////////////////////////////////
unsigned
long longueur_buffer=1024;
char ReadBuffer[1024];
DWORD Nb_RxOctets;
unsigned
long int i,j,k;
unsigned char tx[2], rx[2];
double integration;
int
flag_ampli;
int ampli;
int obturateur;
int inv_obturateur;
int
nb_fastvidage;
int kaf,i_prog,speed;
int x1,y1,x2,y2,bin_x,bin_y;
int imax,jmax;
///////////////////////////
//// Acquisition
parameters
///////////////////////////
i_prog = 1; // prog. version
kaf=1;
// 1 = KAF-0400 - 2 = KAF-1600
x1=1; y1=1; x2=kaf*768; y2=kaf*512;
bin_x=1;
// valuable value : 1, 2, 3, 4
bin_y=1;
obturateur=1; // 1 = synchro
- 0 = closed
inv_obturateur=0; // 0 : no inverted - 1 : inverted
nb_fastvidage=2;
// number of fast clear of the CCD - max. 15
ampli=1; // 1=shutdown
during integration time
speed=6: // speed of the interface (value
between 1...15 - standard value=6)
x1=x1/bin_x;
x2=x2/bin_x;
y1=y1/bin_y;
y2=y2/bin_y;
if
(x1<=0) x1=1;
if (y1<=0) y1=1;
if (x2<=0) x2=10;
if (y2<=0)
y2=10;
imax=x2-x1+1;
jmax=y2-y1+1;
if (InitUsb()==PB) exit(-1); // check USB interface
unsigned long nb_pixel = imax*jmax; //
size of the image
int X1_H_1 = x1/256;
int X1_L_2 = (x1-X1_H_1*256)/16;
int
X1_L_1 = x1-X1_H_1*256 - X1_L_2*16;
int X2_H_1 = x2 / 256;
int X2_L_2
= (x2 - X2_H_1 * 256) / 16;
int X2_L_1 = x2 - X2_H_1 * 256 - X2_L_2 * 16;
int
Y1_H_1 = y1/256;
int Y1_L_2 = (y1-Y1_H_1*256)/16;
int Y1_L_1 = y1-Y1_H_1*256
- Y1_L_2*16;
int Y2_H_1 = y2 / 256;
int Y2_L_2 = (y2 - Y2_H_1 * 256) /
16;
int Y2_L_1 = y2 - Y2_H_1 * 256 - Y2_L_2 * 16;
tx[0]=0;
tx[1]=i_prog
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=kaf*16;
usbWrite(tx,2,&Nb_RxOctets);
tx[1]=bin_x*16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=bin_y*16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=X1_L_1
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=X1_L_2
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=X1_H_1
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=X2_L_1
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=X2_L_2
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=X2_H_1
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=Y1_L_1
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=Y1_L_2
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=Y1_H_1
* 16;
usbWrite(tx,2,&Nb_RxOctets);
tx[1]=Y2_L_1
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=Y2_L_2
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=Y2_H_1
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=nb_fastvidage
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=obturateur
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[1]=inv_obturateur
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[0]=0;
tx[1]=16*0;
// q1
UsbWrite(tx,2,&Nb_RxOctets);
tx[0]=0;
tx[1]=16*15;
// q2 delay before shutter closing = (q1+16.q2)*10 ms
UsbWrite(tx,2,&Nb_RxOctets);
tx[0]=0;
tx[1]=ampli
* 16;
UsbWrite(tx,2,&Nb_RxOctets);
tx[0]=0;
tx[1]=speed
* 16; // speed of the interface (value
between 1 and 15 - normal value = 6)
UsbWrite(tx,2,&Nb_RxOctets);tx[0]=0;
tx[0]=0;
tx[1]=0;
// reserved
UsbWrite(tx,2,&Nb_RxOctets);
tx[0]=0;
tx[1]=0;
// reserved
UsbWrite(tx,2,&Nb_RxOctets);
tx[0]=0;
tx[1]=0;
// reserved
UsbWrite(tx,2,&Nb_RxOctets);
////////////////
// Clear the CCD
////////////////
k=0;
UsbGetQueueStatus(&Nb_RxOctets);
while
(Nb_RxOctets==0)
{
UsbGetQueueStatus(&Nb_RxOctets);
sleep(100); // TimeOut
k++;
if (k==200)
{
msg("USB
interface not ready");
CloseUsb();
exit(-1);
}
}
UsbRead(rx,1,&Nb_RxOctets);
if ((rx[0]
& 240) / 16 != 11)
{
msg("Data transmission
error");
CloseUsb();
exit(-1);
}
///////////
// Exposure
///////////
// Your code...
//////////////////
// End of exposure
//////////////////
tx[0]=0;
tx[1]=255;
UsbWrite(tx,2,&Nb_RxOctets);
// ampli on
sleep(100); // delay
tx[0]=0;
tx[1]=255;
UsbWrite(tx,2,&Nb_RxOctets);
// close shutter
//////////////////////
// Image
read
//////////////////////
// p is a pointer to a short type buffer
of size (imax,jmax)
j=0;
k=0;
int v1,v2,v3,v4,v;
while (j<=4*nb_pixel-longueur_buffer)
{
UsbGetQueueStatus(&Nb_RxOctets);
while
(Nb_RxOctets<longueur_buffer) UsbGetQueueStatus(&Nb_RxOctets);
UsbRead(ReadBuffer,longueur_buffer,&Nb_RxOctets);
for (i=0;i<Nb_RxOctets;i+=4)
{
v1=(int)ReadBuffer[i] & 15;
v2=(int)ReadBuffer[i+1]
& 15;
v3=(int)ReadBuffer[i+2] & 15;
v4=(int)ReadBuffer[i+3] & 15;
v=v1+16*v2+256*v3+4096*v4;
if (v>32767)
p[k]=32767;
else
p[k]=(short)v;
k++;
}
j=j+longueur_buffer;
}
if (j!=4*nb_pixel)
{
UsbGetQueueStatus(&Nb_RxOctets);
while (Nb_RxOctets<4*nb_pixel-j) UsbGetQueueStatus(&Nb_RxOctets);
UsbRead(ReadBuffer,4*nb_pixel-j,&Nb_RxOctets);
for
(i=0;i<Nb_RxOctets;i+=4)
{
v1=(int)ReadBuffer[i]
& 15;
v2=(int)ReadBuffer[i+1] &
15;
v3=(int)ReadBuffer[i+2] & 15;
v4=(int)ReadBuffer[i+3] & 15;
v=v1+16*v2+256*v3+4096*v4;
if (v>32767)
p[k]=32767;
else
p[k]=(short)v;
k++;
}
}
CloseUsb();
/********* InitUsb ***********/
int
InitUsb()
{
if (UsbOpen(0)!=0)
{
msg("USB
not Ok");
return(PB);
}
UsbResetDevice();
return(OK);
}
/*********** CloseUsb **********/
int
CloseUsb()
{
UsbClose();
return(OK);
}
//********************************************************************
int
UsbRead(LPVOID lpvBuffer, DWORD dwBuffSize, LPDWORD lpdwBytesRead)
{
return
(*g_usb_Read)(UsbHandle,lpvBuffer,dwBuffSize,lpdwBytesRead);
}
//********************************************************************
int
UsbWrite(LPVOID lpvBuffer,DWORD dwBuffSize,LPDWORD lpdwBytes)
{
return
(*g_usb_Write)(UsbHandle,lpvBuffer,dwBuffSize,lpdwBytes);
}
//********************************************************************
int
UsbOpen(PVOID pvDevice)
{
return (*g_usb_Open)(pvDevice,&UsbHandle);
}
//********************************************************************
int
UsbClose()
{
return (*g_usb_Close)(UsbHandle);
}
//********************************************************************
int
UsbResetDevice()
{
return (*g_usb_ResetDevice)(UsbHandle);
}
//*********************************************************************
int
UsbGetQueueStatus(LPDWORD lpdwAmountInRxQueue)
{
return (*g_usb_GetQueueStatus)(UsbHandle,lpdwAmountInRxQueue);
}
/****************** OPEN_LIBFTDI ******************/
/*
Load FTDI library */
/**************************************************/
int
open_libftdi(void)
{
g_usb_module=LoadLibrary("Ftd2xx.dll");
if
(g_usb_module == NULL)
{
AfxMessageBox("Error:
Can't Load ft8u245.dll");
return 1;
}
g_usb_Write=(PtrToWrite)GetProcAddress(g_usb_module,
"FT_Write");
if (g_usb_Write == NULL)
{
AfxMessageBox("Error:
Can't Find FT_Write");
return 1;
}
g_usb_Read
= (PtrToRead)GetProcAddress(g_usb_module, "FT_Read");
if (g_usb_Read
== NULL)
{
AfxMessageBox("Error: Can't
Find FT_Read");
return 1;
}
g_usb_Open = (PtrToOpen)GetProcAddress(g_usb_module,
"FT_Open");
if (g_usb_Open == NULL)
{
AfxMessageBox("Error:
Can't Find FT_Open");
return 1;
}
g_usb_Close = (PtrToClose)GetProcAddress(g_usb_module,
"FT_Close");
if (g_usb_Close == NULL)
{
AfxMessageBox("Error:
Can't Find FT_Close");
return 1;
}
g_usb_ResetDevice = (PtrToResetDevice)GetProcAddress(g_usb_module,
"FT_ResetDevice");
if (g_usb_ResetDevice == NULL)
{
AfxMessageBox("Error: Can't Find FT_ResetDevice");
return 1;
}
g_usb_GetQueueStatus = (PtrToGetQueueStatus)GetProcAddress(g_usb_module,
"FT_GetQueueStatus");
if (g_usb_GetQueueStatus == NULL)
{
AfxMessageBox("Error: Can't Find FT_GetQueueStatus");
return 1;
}
return 0;
}
/************** CLOSE_LIBFTDI *************/
/*
Libère la librairie FTDI de la mémoire */
/******************************************/
int
close_libftdi(void)
{
FreeLibrary(g_usb_module);
return(0);
}