MARMEX-VB : "Mary Camera module" library

Dependents:   MARMEX_VB_test MARMEX_VB_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MARMEX_VB.cpp Source File

MARMEX_VB.cpp

00001 /** MARMEX_VB Camera control library
00002  *
00003  *  @class   MARMEX_VB
00004  *  @version 0.5
00005  *  @date    20-Jun-2014
00006  *
00007  *  Released under the Apache License, Version 2.0 : http://mbed.org/handbook/Apache-Licence
00008  *
00009  *  MARMEX_VB Camera control library for mbed
00010  */
00011 
00012 #include    "mbed.h"
00013 #include    "MARMEX_VB.h"
00014 
00015 #define     SPI_FREQUENCY                   (12 * 1000 * 1000)
00016 
00017 /*  
00018  *  Followings are 3 types of line read routines.
00019  *  Choose one of next 3 methods for reading camera data trough SPI interface
00020  *
00021  *  Type0: "LINE_READ_OPT" is define as "NO_OPTIMIZATION"
00022  *      Most basic loop to explain how the MCU reading the line data.
00023  *      But this routine is slow, because the loop does 1 byte read
00024  *      with ChipSelect signal assertion/deassertion by DigitalOut
00025  *
00026  *  Type1: "LINE_READ_OPT" is define as "LOOP_UNROLL"
00027  *      Faster. And keeping compatibility on mbed-SDK.
00028  *      Data reading speed improvement has been done in two ways.
00029  *          * The ChipSelect signal is kept asserted for whole line data transfer.
00030  *            because the MARMEX-VB module does not need deassertion at each end of byte transfer.
00031  *          * Loop unrolled. minimized loop overhead
00032  *
00033  *  Type2: "LINE_READ_OPT" is define as "USING_SSP_FIFO"
00034  *      Fastest but no compatibility with mbed-SDK.
00035  *      The optimization has been done to use FIFO of SSP block.
00036  *      This code makes data transfer efficiency maximum.
00037  *      However, since this optimization is done in very low level (by register accessing),
00038  *      it works on some MCU's only (test has been done on LPC1768, LPC11U24 and LPC11U35).
00039  *
00040  *      And user need to care about which SSP block is used. For instance, if the SPI pins
00041  *      of p5, p6 and p7 are used, those are connected to SSP1 in LPC1768. In case of
00042  *      LPC11U24 and LPC11U35, those pins are routed to SSP0.
00043  *      These settings should be done manually
00044  */
00045  
00046 //#define   LINE_READ_OPT   NO_OPTIMIZATION
00047 #define     LINE_READ_OPT   LOOP_UNROLL
00048 //#define   LINE_READ_OPT   USING_SSP_FIFO
00049 
00050 
00051 /*  Setting for "LINE_READ_OPT == USING_SSP_FIFO"
00052  *      Choose one line from next 3 lines when the FIFO option is taken
00053  */
00054 
00055 #define     SSP_AUTO_SELECTION  //  for demo setup on "MAPLE mini type-B (MARM03-BASE)" baseboard (slot2) with a MARMEX_OB module (on slot1)
00056 //#define   SSP_USE_SSP0
00057 //#define   SSP_USE_SSP1
00058 
00059 
00060 
00061 
00062 MARMEX_VB::MARMEX_VB(
00063     PinName SPI_mosi,
00064     PinName SPI_miso,
00065     PinName SPI_sck,
00066     PinName SPI_cs,
00067     PinName cam_reset,
00068     PinName I2C_sda,
00069     PinName I2C_scl
00070 ) :
00071     _spi( SPI_mosi, SPI_miso, SPI_sck ),
00072     _cs( SPI_cs ),
00073     _reset( cam_reset ),
00074     _i2c( I2C_sda, I2C_scl )
00075 {
00076 #ifdef IGNORE_INITIALIZATION_ERROR
00077     init();
00078 #else
00079     if ( 0 != init() )
00080         error( "camera initialization failed." );
00081 #endif
00082 }
00083 
00084 
00085 #define CAM_I2C_ADDR    0x42
00086 
00087 #define     COMMAND_WRITE                   0x00
00088 #define     COMMAND_READ                    0x80
00089 #define     COMMAND_ADDR_INCREMENT          0x20
00090 
00091 #define     MEMORY_ADDR_LOW__REGISTER       0x0
00092 #define     MEMORY_ADDR_MID__REGISTER       0x1
00093 #define     MEMORY_ADDR_HIGH_REGISTER       0x2
00094 #define     CAMERA_DATA_REGISTER            0x8
00095 #define     CONTROL_DATA_REGISTER           0x3
00096 #define     STATUS_REGISTER                 0x4
00097 
00098 #define     CONTROL__PAUSE_BUFFER_UPDATE    0x01
00099 #define     CONTROL__RESUME_BUFFER_UPDATE   0x00
00100 
00101 
00102 int MARMEX_VB::init( CameraResolution  res )
00103 {
00104 #define     PARAM_NUM               99
00105 #define     RES_CHANGE_PARAM_NUM    12
00106 #define     RESET_PULSE_WIDTH       100     //  mili-seconds
00107 #define     RESET_RECOVERY_TIME     100     //  mili-seconds
00108 #define     COMMAND_INTERVAL        20      //  mili-seconds
00109 
00110     char camera_register_setting[ PARAM_NUM ][ 2 ] = {
00111         { 0x01, 0x40 }, { 0x02, 0x60 }, { 0x03, 0x02 }, { 0x0C, 0x0C },
00112         { 0x0E, 0x61 }, { 0x0F, 0x4B }, { 0x11, 0x80 }, { 0x12, 0x04 },
00113         { 0x15, 0x00 }, { 0x16, 0x02 }, { 0x17, 0x39 }, { 0x18, 0x03 },
00114         { 0x19, 0x03 }, { 0x1A, 0x7B }, { 0x1E, 0x37 }, { 0x21, 0x02 },
00115         { 0x22, 0x91 }, { 0x29, 0x07 }, { 0x32, 0x80 }, { 0x33, 0x0B },
00116         { 0x34, 0x11 }, { 0x35, 0x0B }, { 0x37, 0x1D }, { 0x38, 0x71 },
00117         { 0x39, 0x2A }, { 0x3B, 0x12 }, { 0x3C, 0x78 }, { 0x3D, 0xC3 },
00118         { 0x3E, 0x11 }, { 0x3F, 0x00 }, { 0x40, 0xD0 }, { 0x41, 0x08 },
00119         { 0x41, 0x38 }, { 0x43, 0x0A }, { 0x44, 0xF0 }, { 0x45, 0x34 },
00120         { 0x46, 0x58 }, { 0x47, 0x28 }, { 0x48, 0x3A }, { 0x4B, 0x09 },
00121         { 0x4C, 0x00 }, { 0x4D, 0x40 }, { 0x4E, 0x20 }, { 0x4F, 0x80 },
00122         { 0x50, 0x80 }, { 0x51, 0x00 }, { 0x52, 0x22 }, { 0x53, 0x5E },
00123         { 0x54, 0x80 }, { 0x56, 0x40 }, { 0x58, 0x9E }, { 0x59, 0x88 },
00124         { 0x5A, 0x88 }, { 0x5B, 0x44 }, { 0x5C, 0x67 }, { 0x5D, 0x49 },
00125         { 0x5E, 0x0E }, { 0x69, 0x00 }, { 0x6A, 0x40 }, { 0x6B, 0x0A },
00126         { 0x6C, 0x0A }, { 0x6D, 0x55 }, { 0x6E, 0x11 }, { 0x6F, 0x9F },
00127         { 0x70, 0x3A }, { 0x71, 0x35 }, { 0x72, 0x11 }, { 0x73, 0xF1 },
00128         { 0x74, 0x10 }, { 0x75, 0x05 }, { 0x76, 0xE1 }, { 0x77, 0x01 },
00129         { 0x78, 0x04 }, { 0x79, 0x01 }, { 0x8D, 0x4F }, { 0x8E, 0x00 },
00130         { 0x8F, 0x00 }, { 0x90, 0x00 }, { 0x91, 0x00 }, { 0x96, 0x00 },
00131         { 0x96, 0x00 }, { 0x97, 0x30 }, { 0x98, 0x20 }, { 0x99, 0x30 },
00132         { 0x9A, 0x00 }, { 0x9A, 0x84 }, { 0x9B, 0x29 }, { 0x9C, 0x03 },
00133         { 0x9D, 0x4C }, { 0x9E, 0x3F }, { 0xA2, 0x52 }, { 0xA4, 0x88 },
00134         { 0xB0, 0x84 }, { 0xB1, 0x0C }, { 0xB2, 0x0E }, { 0xB3, 0x82 },
00135         { 0xB8, 0x0A }, { 0xC8, 0xF0 }, { 0xC9, 0x60 },
00136     };
00137     const char  res_change_param[ 5 ][ RES_CHANGE_PARAM_NUM ] = {
00138         { 0x17, 0x18, 0x32, 0x19, 0x1a, 0x03, 0x0c, 0x3e, 0x71, 0x72, 0x73, 0xa2 }, //  register addr
00139         { 0x39, 0x03, 0x80, 0x03, 0x7b, 0x02, 0x0c, 0x11, 0x35, 0x11, 0xf1, 0x52 }, //  QSIF
00140         { 0x13, 0x01, 0xb6, 0x02, 0x7a, 0x0a, 0x00, 0x00, 0x35, 0x11, 0xf0, 0x02 }, //  VGA
00141         { 0x16, 0x04, 0x80, 0x02, 0x7a, 0x0a, 0x04, 0x19, 0x35, 0x11, 0xf1, 0x02 }, //  QVGA
00142         { 0x16, 0x04, 0xa4, 0x02, 0x7a, 0x0a, 0x04, 0x1a, 0x35, 0x22, 0xf2, 0x02 }, //  QQVGA
00143     };
00144     const char camera_reset_command[] = { 0x12, 0x80 };
00145 
00146     _read_order_change  = 0;
00147 
00148     //  SPI settings
00149 
00150 
00151     _cs     = 1;                        //  set ChipSelect signal HIGH
00152     _spi.format( 8 );                   //  camera SPI : 8bits/transfer
00153     _spi.frequency( SPI_FREQUENCY );    //  SPI frequency setting
00154     _i2c.frequency( 400 * 1000 );
00155 
00156     //  reset
00157 
00158     _reset = 0;
00159     wait_ms( RESET_PULSE_WIDTH );   //  assert RESET signal
00160     _reset = 1;
00161     wait_ms( RESET_RECOVERY_TIME ); //  deassert RESET signal
00162 
00163     if ( 0 != (_error_state = _i2c.write( CAM_I2C_ADDR, camera_reset_command, 2 )) )
00164         return _error_state;    //  return non-zero if I2C access failed
00165 
00166     wait_ms( 100 ); //  reset (via I2C) recovery time
00167 
00168     _horizontal_size    = QCIF_PIXEL_PER_LINE;
00169     _vertical_size      = QCIF_LINE_PER_FRAME;
00170 
00171 #ifdef UNIFIED_RESOLUTION_CHANGE
00172     if ( QCIF != res ) {
00173         for ( int i = 0; i < RES_CHANGE_PARAM_NUM; i++ ) {
00174             for ( int j = 0; j < PARAM_NUM; j++ ) {
00175                 if ( camera_register_setting[ j ][ 0 ] == res_change_param[ 0 ][ i ] ) {
00176                     camera_register_setting[ j ][ 1 ]   = res_change_param[ res ][ i ];
00177                 }
00178             }
00179         }
00180     }
00181 
00182     switch ( res ) {
00183         case QCIF:
00184             _horizontal_size    = QCIF_PIXEL_PER_LINE;
00185             _vertical_size      = QCIF_LINE_PER_FRAME;
00186             break;
00187         case VGA:
00188             _horizontal_size    = VGA_PIXEL_PER_LINE;
00189             _vertical_size      = VGA_LINE_PER_FRAME;
00190             break;
00191         case QVGA:
00192             _horizontal_size    = VGA_PIXEL_PER_LINE / 2;
00193             _vertical_size      = VGA_LINE_PER_FRAME / 2;
00194             break;
00195         case QQVGA:
00196             _horizontal_size    = VGA_PIXEL_PER_LINE / 4;
00197             _vertical_size      = VGA_LINE_PER_FRAME / 4;
00198             break;
00199     }
00200 #endif
00201 
00202 
00203     for ( int i = 0; i < PARAM_NUM; i++ ) {
00204         if ( 0 != (_error_state = _i2c.write( CAM_I2C_ADDR, camera_register_setting[ i ], 2 )) )
00205             break;
00206 
00207         wait_ms( COMMAND_INTERVAL );  //  camera register writing requires this interval
00208     }
00209 
00210 #ifndef UNIFIED_RESOLUTION_CHANGE
00211     if ( QCIF != res ) {
00212         char    d[ 2 ];
00213         for ( int i = 0; i < RES_CHANGE_PARAM_NUM; i++ ) {
00214             d[ 0 ]  = res_change_param[  0  ][ i ];
00215             d[ 1 ]  = res_change_param[ res ][ i ];
00216 
00217             if ( 0 != (_error_state = _i2c.write( CAM_I2C_ADDR, d, 2 )) )
00218                 break;
00219 
00220             wait_ms( COMMAND_INTERVAL );  //  camera register writing requires this interval
00221         }
00222     }
00223 
00224     switch ( res ) {
00225         case QCIF:
00226             _horizontal_size    = QCIF_PIXEL_PER_LINE;
00227             _vertical_size      = QCIF_LINE_PER_FRAME;
00228             break;
00229         case VGA:
00230             _horizontal_size    = VGA_PIXEL_PER_LINE;
00231             _vertical_size      = VGA_LINE_PER_FRAME;
00232             break;
00233         case QVGA:
00234             _horizontal_size    = VGA_PIXEL_PER_LINE / 2;
00235             _vertical_size      = VGA_LINE_PER_FRAME / 2;
00236             break;
00237         case QQVGA:
00238             _horizontal_size    = VGA_PIXEL_PER_LINE / 4;
00239             _vertical_size      = VGA_LINE_PER_FRAME / 4;
00240             break;
00241     }
00242 #endif
00243 
00244     return _error_state;    //  return non-zero if I2C access failed
00245 }
00246 
00247 void MARMEX_VB::colorbar( SwitchState  sw )
00248 {
00249     char    s[ 2 ];
00250 
00251     s[ 0 ]  = 0x12;
00252     s[ 1 ]  = sw ? 0x06 : 0x04;
00253 
00254     _error_state = _i2c.write( CAM_I2C_ADDR, s, 2 );
00255 }
00256 
00257 int MARMEX_VB::get_horizontal_size( void )
00258 {
00259     return _horizontal_size;    //  return last state of I2C access
00260 }
00261 
00262 int MARMEX_VB::get_vertical_size( void )
00263 {
00264     return _vertical_size;    //  return last state of I2C access
00265 }
00266 
00267 int MARMEX_VB::ready( void )
00268 {
00269     return _error_state;    //  return last state of I2C access
00270 }
00271 
00272 extern int read_order_change;
00273 
00274 void MARMEX_VB::read_a_line( short *p, int line_number, int x_offset, int n_of_pixels )
00275 {    
00276     //  OPTION REFERENCE NUMBER (DO NOT EDIT)
00277     #define NO_OPTIMIZATION 0
00278     #define LOOP_UNROLL     1
00279     #define USING_SSP_FIFO  2
00280 
00281     if ( line_number < 0 )
00282         return;
00283 
00284     //  set camera module's buffer address
00285     set_address( line_number * get_horizontal_size() * BYTE_PER_PIXEL + x_offset * BYTE_PER_PIXEL );
00286 
00287     //  put a read command, first return byte should be ignored
00288     read_register( CAMERA_DATA_REGISTER );
00289 
00290 
00291 /*
00292  *  Type0: "LINE_READ_OPT" is define as "NO_OPTIMIZATION"
00293  *      Most basic loop to explain how the MCU reading the line data.
00294  *      But this routine is slow, because the loop does 1 byte read
00295  *      with ChipSelect signal assertion/deassertion by DigitalOut
00296  */
00297 #if ( LINE_READ_OPT == NO_OPTIMIZATION )
00298 
00299     short    tmp;
00300 
00301     if ( _read_order_change ) {
00302         for( int x = 0; x < n_of_pixels; x++ ) {
00303             //  perform 2 bytes read. a pixel data is in RGB565 format (16bits)
00304             tmp     = read_register( CAMERA_DATA_REGISTER );                //  read lower byte
00305             *p++    = (read_register( CAMERA_DATA_REGISTER ) << 8) | tmp;   //  read upper byte
00306         }
00307     } else {
00308 
00309         read_register( CAMERA_DATA_REGISTER );
00310 
00311         for( int x = 0; x < n_of_pixels; x++ ) {
00312             //  perform 2 bytes read. a pixel data is in RGB565 format (16bits)
00313             tmp     = read_register( CAMERA_DATA_REGISTER ) << 8;                //  read lower byte
00314             *p++    = (read_register( CAMERA_DATA_REGISTER ) << 0) | tmp;   //  read upper byte
00315         }
00316     }
00317 #endif  //  ( LINE_READ_OPT == NO_OPTIMIZATION )
00318 
00319 
00320 /*
00321  *  Type1: "LINE_READ_OPT" is define as "LOOP_UNROLL"
00322  *      Faster. And keeping compatibility on mbed-SDK.
00323  *      Data reading speed improvement has been done in two ways.
00324  *          * The ChipSelect signal is kept asserted for whole line data transfer.
00325  *            because the MARMEX-VB module does not need deassertion at each end of byte transfer.
00326  *          * Loop unrolled. minimized loop overhead
00327  */
00328 #if ( LINE_READ_OPT == LOOP_UNROLL )
00329 
00330     char    reg = COMMAND_READ | CAMERA_DATA_REGISTER | COMMAND_ADDR_INCREMENT;
00331 
00332     if ( _read_order_change ) {
00333 
00334         _cs = 0;
00335     
00336         for( int x = 0; x < n_of_pixels; x += 8 ) {
00337             //  perform 2 bytes read. a pixel data is in RGB565 format (16bits)
00338     
00339             *p      = _spi.write( reg );
00340             *p++   |= _spi.write( reg ) << 8;
00341     
00342             *p      = _spi.write( reg );
00343             *p++   |= _spi.write( reg ) << 8;
00344     
00345             *p      = _spi.write( reg );
00346             *p++   |= _spi.write( reg ) << 8;
00347     
00348             *p      = _spi.write( reg );
00349             *p++   |= _spi.write( reg ) << 8;
00350     
00351             *p      = _spi.write( reg );
00352             *p++   |= _spi.write( reg ) << 8;
00353     
00354             *p      = _spi.write( reg );
00355             *p++   |= _spi.write( reg ) << 8;
00356     
00357             *p      = _spi.write( reg );
00358             *p++   |= _spi.write( reg ) << 8;
00359     
00360             *p      = _spi.write( reg );
00361             *p++   |= _spi.write( reg ) << 8;
00362     
00363         }
00364         _cs = 1;
00365 
00366     } else {
00367         
00368         read_register( CAMERA_DATA_REGISTER );
00369 
00370         _cs = 0;
00371     
00372         for( int x = 0; x < n_of_pixels; x += 8 ) {
00373             //  perform 2 bytes read. a pixel data is in RGB565 format (16bits)
00374     
00375             *p      = _spi.write( reg ) << 8;
00376             *p++   |= _spi.write( reg );
00377     
00378             *p      = _spi.write( reg ) << 8;
00379             *p++   |= _spi.write( reg );
00380     
00381             *p      = _spi.write( reg ) << 8;
00382             *p++   |= _spi.write( reg );
00383     
00384             *p      = _spi.write( reg ) << 8;
00385             *p++   |= _spi.write( reg );
00386     
00387             *p      = _spi.write( reg ) << 8;
00388             *p++   |= _spi.write( reg );
00389     
00390             *p      = _spi.write( reg ) << 8;
00391             *p++   |= _spi.write( reg );
00392     
00393             *p      = _spi.write( reg ) << 8;
00394             *p++   |= _spi.write( reg );
00395     
00396             *p      = _spi.write( reg ) << 8;
00397             *p++   |= _spi.write( reg );
00398     
00399         }
00400         _cs = 1;
00401     }
00402 #endif  //  ( LINE_READ_OPT == LOOP_UNROLL )
00403 
00404 
00405 /*
00406  *  Type2: "LINE_READ_OPT" is define as "USING_SSP_FIFO"
00407  *      Fastest but no compatibility with mbed-SDK.
00408  *      The optimization has been done to use FIFO of SSP block.
00409  *      This code makes data transfer efficiency maximum.
00410  *      However, since this optimization is done in very low level (by register accessing),
00411  *      it works on some MCU's only (test has been done on LPC1768, LPC11U24 and LPC11U35).
00412  *
00413  *      And user need to care about which SSP block is used. For instance, if the SPI pins
00414  *      of p5, p6 and p7 are used, those are connected to SSP1 in LPC1768. In case of
00415  *      LPC11U24 and LPC11U35, those pins are routed to SSP0.
00416  *      These settings should be done manually
00417  */
00418 #if ( LINE_READ_OPT == USING_SSP_FIFO )
00419 
00420     #define FIFO_DEPTH  4
00421 
00422     #if defined( SSP_AUTO_SELECTION )
00423         #if defined( TARGET_MBED_LPC1768 )
00424             #define SPI_PORT_SELECTOR   LPC_SSP1
00425         #elif defined( TARGET_LPC11U35_501 ) || defined( TARGET_LPC11U24_401 )
00426             #define SPI_PORT_SELECTOR   LPC_SSP0
00427         #endif
00428     #elif defined( SSP_USE_SSP0 )
00429         #define SPI_PORT_SELECTOR   LPC_SSP0
00430     #elif defined( SSP_USE_SSP1 )
00431         #define SPI_PORT_SELECTOR   LPC_SSP1
00432     #else
00433         #error when using FIFO option for the optimization, choose one of definition from SSP_AUTO_SELECTION, SSP_USE_SSP0 or SSP_USE_SSP1
00434     #endif   //  #if defined( SSP_AUTO_SELECTION )
00435 
00436     char    reg = COMMAND_READ | CAMERA_DATA_REGISTER | COMMAND_ADDR_INCREMENT;
00437     int     n;
00438 
00439     if ( _read_order_change ) {
00440         
00441         _cs = 0;
00442 
00443         for(n = FIFO_DEPTH; n > 0; n--) {
00444             SPI_PORT_SELECTOR->DR = reg;
00445         }
00446 
00447         do {
00448             while (!(SPI_PORT_SELECTOR->SR & 0x4));
00449             *p  = (SPI_PORT_SELECTOR->DR & 0xFF);
00450 
00451             if (n++ < (n_of_pixels << 1) - FIFO_DEPTH)
00452                 SPI_PORT_SELECTOR->DR = reg;
00453 
00454             while (!(SPI_PORT_SELECTOR->SR & 0x4));
00455             *p++    |= (SPI_PORT_SELECTOR->DR << 8);
00456 
00457             if (n++ < (n_of_pixels << 1) - FIFO_DEPTH)
00458                 SPI_PORT_SELECTOR->DR = reg;
00459 
00460         } while(n < (n_of_pixels << 1));
00461 
00462         _cs = 1;
00463         
00464     } else {
00465         
00466         read_register( CAMERA_DATA_REGISTER );
00467 
00468         _cs = 0;
00469 
00470         for(n = FIFO_DEPTH; n > 0; n--) {
00471             SPI_PORT_SELECTOR->DR = reg;
00472         }
00473 
00474         do {
00475             while (!(SPI_PORT_SELECTOR->SR & 0x4));
00476             *p = (SPI_PORT_SELECTOR->DR << 8);
00477 
00478             if (n++ < (n_of_pixels << 1) - FIFO_DEPTH)
00479                 SPI_PORT_SELECTOR->DR = reg;
00480 
00481             while (!(SPI_PORT_SELECTOR->SR & 0x4));
00482             *p++ |= (SPI_PORT_SELECTOR->DR & 0xFF);
00483 
00484             if (n++ < (n_of_pixels << 1) - FIFO_DEPTH)
00485                 SPI_PORT_SELECTOR->DR = reg;
00486 
00487         } while(n < (n_of_pixels << 1));
00488 
00489         _cs = 1;
00490     }
00491 
00492 #endif  //  ( LINE_READ_OPT == USING_SSP_FIFO )
00493 }
00494 
00495 void MARMEX_VB::open_transfer( void )
00496 {
00497     //  send command to pause the camera buffer update
00498     write_register( CONTROL_DATA_REGISTER, CONTROL__PAUSE_BUFFER_UPDATE );
00499 
00500     //  read status register (first return byte should be ignored)
00501     read_register( STATUS_REGISTER );
00502 
00503     //  wait until the status register become 0x51(ready to transfer data)
00504     while ( 0x51 != read_register( STATUS_REGISTER ) )
00505         ;
00506 }
00507 
00508 void MARMEX_VB::close_transfer( void )
00509 {
00510     //  send command to resume the camera buffer update
00511     write_register( CONTROL_DATA_REGISTER, CONTROL__RESUME_BUFFER_UPDATE );
00512 
00513     //  read status register (first return byte should be ignored)
00514     read_register( STATUS_REGISTER );
00515 
00516     //  wait until the status register become 0x50(camera updating the buffer)
00517     while ( 0x50 != read_register( STATUS_REGISTER ) )
00518         ;
00519 }
00520 
00521 int MARMEX_VB::read_order_change( void )
00522 {
00523     return ( _read_order_change = !_read_order_change );
00524 }
00525 
00526 void MARMEX_VB::set_address( int address )
00527 {
00528     //  set memory address (3 bytes)
00529 
00530     write_register( MEMORY_ADDR_LOW__REGISTER, (address >>  0) & 0xFF );
00531     write_register( MEMORY_ADDR_MID__REGISTER, (address >>  8) & 0xFF );
00532     write_register( MEMORY_ADDR_HIGH_REGISTER, (address >> 16) & 0xFF );
00533 }
00534 
00535 void MARMEX_VB::write_register( char reg, char value )
00536 {
00537     //  camera register write
00538 
00539     send_spi( COMMAND_WRITE | reg );    //  send command and register number
00540     send_spi( value );                  //  send register value
00541 }
00542 
00543 int MARMEX_VB::read_register( char reg )
00544 {
00545     //  camera register read
00546     //  returning current data in SPI buffer (data returned by previous command)
00547 
00548     return ( send_spi( COMMAND_READ | reg | ((reg == CAMERA_DATA_REGISTER) ? COMMAND_ADDR_INCREMENT : 0x00) ) );
00549 }
00550 
00551 int MARMEX_VB::send_spi( char data )
00552 {
00553     int     tmp;
00554 
00555     //  SPI access
00556     _cs     = 0;
00557     tmp     = _spi.write( data );
00558     _cs     = 1;
00559 
00560     return ( tmp );
00561 }