Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

kernel/HOLD/dsensor.c

Go to the documentation of this file.
00001 
00006 /*
00007  *  The contents of this file are subject to the Mozilla Public License
00008  *  Version 1.0 (the "License"); you may not use this file except in
00009  *  compliance with the License. You may obtain a copy of the License at
00010  *  http://www.mozilla.org/MPL/
00011  *
00012  *  Software distributed under the License is distributed on an "AS IS"
00013  *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
00014  *  License for the specific language governing rights and limitations
00015  *  under the License.
00016  *
00017  *  The Original Code is legOS code, released October 17, 1999.
00018  *
00019  *  The Initial Developer of the Original Code is Markus L. Noga.
00020  *  Portions created by Markus L. Noga are Copyright (C) 1999
00021  *  Markus L. Noga. All Rights Reserved.
00022  *
00023  *  Contributor(s): Markus L. Noga <markus@noga.de>
00024  *                  Eric Habnerfeller <ehaberfe@atitech.ca>
00025  *                  Lou Sortman <lou@sunsite.unc.edu>
00026  */
00027 
00028 /*
00029  *  2000.03.11 - Paolo Masetti <paolo.masetti@itlug.org>
00030  *
00031  *      - Included a fix for rotation sensor posted by "Ben Jackson"
00032  *        on lugnet.robotics.rcx.legos
00033  *
00034  *  2000.04.30 - Paolo Masetti <paolo.masetti@itlug.org>
00035  *
00036  *      - ISR Reading routine fix to make read values stable.
00037  *      - Fixed rotation sensor status table values to avoid offset problems.
00038  *
00039  *  2000.09.06 - Jochen Hoenicke <jochen@gnu.org>
00040  *
00041  *      - Added velocity calculation for rotation sensor.
00042  */
00043 
00044 #include <dsensor.h>
00045 
00046 #ifdef CONF_DSENSOR
00047 
00048 #include <sys/h8.h>
00049 #include <sys/irq.h>
00050 #include <sys/bitops.h>
00051 #include <rom/registers.h>
00052 #include <unistd.h>
00053 #include <conio.h>
00054 
00056 //
00057 // Definitions
00058 //
00060 
00061 #define DS_ALL_ACTIVE         0x07             
00062 #define DS_ALL_PASSIVE        (~DS_ALL_ACTIVE) 
00063 
00064 
00065 //
00066 // Variables
00067 //
00069 
00070 volatile unsigned char ds_channel;        
00071 
00072 unsigned char ds_activation;              
00073 
00074 #ifdef CONF_DSENSOR_ROTATION
00075 unsigned char ds_rotation;                
00076 
00077 volatile int ds_rotations[3];             
00078 
00079 static signed char rotation_state[3];     
00080 static signed char rotation_new_state[3]; 
00081 static unsigned int state_duration[3];    
00082 
00083 #ifdef CONF_DSENSOR_VELOCITY
00084 volatile int ds_velocities[3];            
00085 static unsigned int last_rotation[3];     
00086 static unsigned int next_rotation[3];     
00087 static signed char rotation_dir[3];       
00088 #endif
00089 
00090 
00091 
00093 
00096 static const signed char ad2state[16]={
00097   // 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f     // (sensor value>>12)
00098     -1,-1,-1,-1,-1, 2, 2, 2, 3, 3, 3, 3, 1, 1, 1, 0     // New values to be used
00099                                                         // with delayed read
00100 
00101 //  -1,-1,-1,-1,-1,-1, 2, 2, 2, 3, 3, 3, 1, 1, 1, 0     // Old values: biased for
00102                                                         // non-delayed read
00103 
00104 };
00105 
00107 
00112 static const signed char diff2change[7]={
00113   //-3 -2 -1  0  1  2  3                              // newstate-state
00114      1, 0,-1, 0, 1, 0,-1
00115 };
00116 
00118 //
00119 // Functions
00120 //
00122 
00124 
00126 void ds_active(volatile unsigned *sensor)
00127 {
00128   if (sensor == &SENSOR_3)
00129     bit_set(&ds_activation, 0);
00130   else if (sensor == &SENSOR_2)
00131     bit_set(&ds_activation, 1);
00132   else if (sensor == &SENSOR_1)
00133     bit_set(&ds_activation, 2);
00134 }
00135 
00137 
00139 void ds_passive(volatile unsigned *sensor)
00140 {
00141   if (sensor == &SENSOR_3) {
00142     bit_clear(&ds_activation, 0);
00143     bit_clear(&PORT6, 0);
00144   } else if (sensor == &SENSOR_2) {
00145     bit_clear(&ds_activation, 1);
00146     bit_clear(&PORT6, 1);
00147   }  else if (sensor == &SENSOR_1) {
00148     bit_clear(&ds_activation, 2);
00149     bit_clear(&PORT6, 2);
00150   }
00151 }
00152 
00153 #ifdef CONF_DSENSOR_ROTATION
00154 
00156 
00158 void ds_rotation_on(volatile unsigned *sensor)
00159 {
00160   if (sensor == &SENSOR_3)
00161     bit_set(&ds_rotation, 0);
00162   else if (sensor == &SENSOR_2)
00163     bit_set(&ds_rotation, 1);
00164   else if (sensor == &SENSOR_1)
00165     bit_set(&ds_rotation, 2);
00166 }
00167 
00169 
00171 void ds_rotation_off(volatile unsigned *sensor)
00172 {
00173   if (sensor == &SENSOR_3)
00174     bit_clear(&ds_rotation, 0);
00175   else if (sensor == &SENSOR_2)
00176     bit_clear(&ds_rotation, 1);
00177   else if (sensor == &SENSOR_1)
00178     bit_clear(&ds_rotation, 2);
00179 }
00180 #endif // CONF_DSENSOR_ROTATION
00181 
00182 
00183 #ifdef CONF_DSENSOR_MUX
00184 
00186 
00188 void ds_mux_off(volatile unsigned *sensor)
00189 {
00190   if (sensor == &SENSOR_3)
00191     bit_clear(&ds_mux, 0);
00192   else if (sensor == &SENSOR_2)
00193     bit_clear(&ds_mux, 1);
00194   else if (sensor == &SENSOR_1)
00195     bit_clear(&ds_mux, 2);
00196 }//endof ds_mux_off
00197 
00198 #endif // CONF_DSENSOR_MUX
00199 
00201 
00206 void ds_rotation_set(volatile unsigned *sensor,int pos) {
00207   if(sensor>=&AD_A && sensor<=&AD_C) {    // catch range violations
00208     unsigned channel=(unsigned) (sensor-&AD_A);
00209     signed char state=ad2state[(*sensor)>>12];
00210 
00211     if(state<0)
00212       state=0;
00213 
00214     rotation_state[channel]=state;
00215     rotation_new_state[channel] = -1;
00216     state_duration[channel]=0;
00217     ds_rotations[channel]=pos;            // reset counter
00218 
00219   }
00220 }
00221 
00223 
00225 void ds_rotation_handler() {
00226   unsigned    channel =ds_channel;
00227   unsigned    raw     =(*((&AD_A)+channel));
00228   signed char newstate=ad2state[raw>>12];
00229 
00230   if (newstate < 0)
00231     return;
00232 
00233   if (newstate == rotation_new_state[channel]) {
00234     if (++state_duration[channel] == 2) {
00235       signed char change = diff2change[newstate - rotation_state[channel] + 3];
00236 
00237       ds_rotations[channel] += change;
00238 
00239 #ifdef CONF_DSENSOR_VELOCITY
00240       {
00241         /* We only take the lowest 16 bits of sys_time.  We have to be
00242          * a bit careful with wraparounds, but this is handled here.
00243          */
00244         unsigned int time = (unsigned int) sys_time;
00245         if (change != rotation_dir[channel]) {
00246           rotation_dir[channel] = change;
00247           ds_velocities[channel] = 0;
00248           last_rotation[channel] = time;
00249           next_rotation[channel] = time + 1000;
00250         } else {
00251           if (time == last_rotation[channel])
00252             ds_velocities[channel] = 1000 * change;
00253           else {
00254             unsigned int time_diff = (time - last_rotation[channel]);
00255             if (time_diff > 1000) {
00256               rotation_dir[channel] = 0;
00257               ds_velocities[channel] = 0;
00258             } else {
00259               int speed = 1000 / time_diff;
00260               ds_velocities[channel] = change > 0 ? speed : -speed;
00261               last_rotation[channel] = time;
00262               next_rotation[channel] = time + time_diff * 3 / 2;
00263             }
00264           }
00265         }
00266       }
00267 #endif
00268 
00269       rotation_state[channel] = newstate;
00270       rotation_new_state[channel] = -1;
00271     }
00272   } else if (newstate != rotation_state[channel]) {
00273     rotation_new_state[channel] = newstate;
00274     state_duration[channel] = 1;
00275 #ifdef CONF_DSENSOR_VELOCITY
00276   } else {
00277     /* No rotation change, check if velocity measure timeouts. */
00278     unsigned int time = (unsigned int) sys_time;
00279     if (rotation_dir[channel] &&  
00280         ((signed int) (time - next_rotation[channel])) >= 0) {
00281       unsigned int time_diff = (time - last_rotation[channel]);
00282       if (time_diff > 1000) {
00283         rotation_dir[channel] = 0;
00284         ds_velocities[channel] = 0;
00285       } else {  
00286         int speed = 1000 / time_diff;
00287         ds_velocities[channel] = rotation_dir[channel] > 0 ? speed : -speed;
00288         next_rotation[channel] = time + time_diff / 2;
00289       }
00290     }
00291 #endif
00292   }
00293 
00294 }
00295 #endif // CONF_DSENSOR_ROTATION
00296 
00297 #ifdef CONF_DSENSOR_MUX
00298 unsigned char ds_mux;   
00299 
00300 volatile int ds_muxs[3][3];     
00301 
00302 
00303 //width of each mux pulse
00304 #define DS_MUX_PULSE_TM_MS 10
00305 
00306 
00307 
00308 typedef struct {
00309   unsigned long nextTm;  //timestamp for next pulse
00310   char remainingEdges;    //edges left in pulse train
00311   char channel; //current mux sub channel (0,1,2)
00312   unsigned int attached[3];//what channels are sensors attached to
00313                             //this also defines the number of ms
00314                             //to wait before reading the value
00315   
00316   enum {ds_mux_prepRead,
00317         ds_mux_read, 
00318         ds_mux_pulse_low, 
00319         ds_mux_pulse_high} action; //specify next action
00320 } ds_mux_data_t;
00321 
00322 ds_mux_data_t ds_mux_data[3]; //data on mux
00323 
00324 #endif //CONF_DSENSOR_MUX
00325 
00326 
00327 
00328 static inline void ds_power_on(unsigned channel) {
00329   switch(channel) {
00330   case 0:
00331     bit_set(&PORT6,0);
00332     break;
00333   case 1:
00334     bit_set(&PORT6,1);
00335     break;
00336   case 2:
00337     bit_set(&PORT6,2);
00338     break;
00339   default:
00340     //bad
00341     break;
00342   }
00343 }//endof ds_power_on
00344 
00345 static inline void ds_power_off(unsigned channel) {
00346   switch(channel) {
00347   case 0:
00348     bit_clear(&PORT6,0);
00349     break;
00350   case 1:
00351     bit_clear(&PORT6,1);
00352     break;
00353   case 2:
00354     bit_clear(&PORT6,2);
00355     break;
00356   default:
00357     //bad
00358     break;
00359   }
00360 }//endof ds_power_off
00361 
00362 #ifdef CONF_DSENSOR_MUX
00363 
00364 
00366 void ds_mux_on(volatile unsigned *sensor,
00367                unsigned int ch1,
00368                unsigned int ch2,
00369                unsigned int ch3) {
00370   unsigned char i,j;
00371   ds_passive(sensor);//powered, but not active in legOS sense
00372 
00373 
00374   if(ch1==0 &&
00375      ch2==0 &&
00376      ch3==0) {
00377     //umm this is useless
00378     //avoid endless cycling
00379     ds_mux_off(sensor);
00380     return;
00381   }
00382 
00383   if (sensor == &SENSOR_3) {
00384     i=0;
00385   } else if (sensor == &SENSOR_2) {
00386     i=1;
00387   } else if (sensor == &SENSOR_1) {
00388     i=2;
00389   } else {
00390     //bad
00391     return;
00392   }
00393 
00394   
00395   ds_mux_data[i].attached[0]=ch1;
00396   ds_mux_data[i].attached[1]=ch2;
00397   ds_mux_data[i].attached[2]=ch3;
00398   
00399   //add extended time based on the channel
00400   //this is required by the mux
00401   //the user supplies extra time based on the
00402   //type of sensor they hook up
00403   //these defaults give enough time to read
00404   //a light sensor and should be ok for most
00405   //sensors
00406   if(ch1)
00407     ds_mux_data[i].attached[0]+=160;
00408   if(ch2)
00409     ds_mux_data[i].attached[1]+=135;
00410   if(ch3)
00411     ds_mux_data[i].attached[2]+=25;
00412 
00413 
00414 
00415 
00416   //check if we're just adjusting the ports
00417   //if so we can return here
00418   if(i==0 && ds_mux&1)
00419     return;
00420   if(i==1 && ds_mux&2)
00421     return;
00422   if(i==2 && ds_mux&4)
00423     return;
00424 
00425   //starting up mux
00426 
00427   //power up
00428   ds_power_on(i);
00429   
00430   //schedule first event
00431   //find first attached sensor
00432   for(j=0;j<3 && ds_mux_data[i].attached[j]==0;j++);
00433     
00434   ds_mux_data[i].channel=j;
00435   ds_mux_data[i].remainingEdges=((j+1)*2);
00436   ds_mux_data[i].action=ds_mux_pulse_low;
00437   ds_mux_data[i].nextTm=sys_time+DS_MUX_PULSE_TM_MS;
00438 
00439   if (sensor == &SENSOR_3) {
00440     bit_set(&ds_mux, 0);
00441   } else if (sensor == &SENSOR_2) {
00442     bit_set(&ds_mux, 1);
00443   } else if (sensor == &SENSOR_1) {
00444     bit_set(&ds_mux, 2);
00445   } else {
00446     //bad
00447     return;
00448   }
00449 
00450 }//endof ds_mux_on
00451 
00452 
00453 
00454 void ds_mux_handler() {
00455   unsigned sen=ds_channel;
00456 
00457 
00458   if(ds_mux_data[sen].nextTm <= sys_time) {
00459     //we've reached our next scheduled step
00460     //lcd_int(sys_time-ds_mux_data[sen].nextTm);
00461     switch(ds_mux_data[sen].action) {
00462     case ds_mux_prepRead:
00463       ds_power_off(sen);//power down for read
00464       ds_mux_data[sen].action=ds_mux_read;
00465       ds_mux_data[sen].nextTm=sys_time;//do it ASAP, but not now
00466       break;
00467     case ds_mux_read:
00468       //read data
00469       switch(sen) {
00470       case 0:
00471         ds_muxs[sen][(int)ds_mux_data[sen].channel]=SENSOR_3;
00472         break;
00473       case 1:
00474         ds_muxs[sen][(int)ds_mux_data[sen].channel]=SENSOR_2;
00475         break;
00476       case 2:
00477         ds_muxs[sen][(int)ds_mux_data[sen].channel]=SENSOR_1;
00478         break;
00479       default:
00480         //bad
00481       }
00482 
00483  
00484       //change channel
00485       do {
00486         ds_mux_data[sen].channel++;
00487         if(ds_mux_data[sen].channel>2/*max chan*/) {
00488           ds_mux_data[sen].channel=0;
00489         }
00490         //make sure selected channel is marked attached
00491         //don't worry about an endless loop ds_mux_on makes
00492         //sure at least one channel is attached
00493       } while(
00494               (ds_mux_data[sen].attached
00495                [(int)ds_mux_data[sen].channel])==0);
00496       
00497     
00498       //use this low pulse as the first low pulse of next train
00499 
00500       ds_mux_data[sen].remainingEdges=
00501         ((ds_mux_data[sen].channel+1)*2)-1;
00502 
00503       //schedule next high pulse
00504       ds_mux_data[sen].action=ds_mux_pulse_high;
00505       ds_mux_data[sen].nextTm=sys_time+DS_MUX_PULSE_TM_MS;
00506       break;
00507     case ds_mux_pulse_low:
00508       //go low
00509       ds_power_off(sen);
00510       //schedule next high pulse
00511       ds_mux_data[sen].nextTm=sys_time+DS_MUX_PULSE_TM_MS;
00512       ds_mux_data[sen].remainingEdges--;  
00513       ds_mux_data[sen].action=ds_mux_pulse_high;
00514       break;
00515     case ds_mux_pulse_high:
00516       //go high
00517       ds_power_on(sen);
00518       ds_mux_data[sen].remainingEdges--;      
00519      
00520       if(ds_mux_data[sen].remainingEdges==0) {
00521         //done with train
00522         //schedule prepRead
00523         ds_mux_data[sen].action=ds_mux_prepRead;
00524 
00525         //schedule enough time for the mux to make the switch
00526         //this is scaled because the timeout the mux uses starts
00527         //when the first pulse comes in, it is around 70ms, so
00528         //when switching to sensor 1 we must want an additional
00529         //amount of time before it mux reacts, we wait less for 2
00530         //and not at all for 3
00531         //then we wait a little bit before reading the sensor
00532         //this give the sensor time to power up
00533         ds_mux_data[sen].nextTm=sys_time+
00534           ds_mux_data[sen].attached[(int)ds_mux_data[sen].channel];
00535         //lcd_int(ds_mux_data[sen].channel+1);
00536 
00537         break;
00538       } else {
00539         //schedule next low pulse
00540         ds_mux_data[sen].action=ds_mux_pulse_low;
00541         ds_mux_data[sen].nextTm=sys_time+DS_MUX_PULSE_TM_MS;
00542       }      
00543       break;
00544     default:
00545       //bad
00546     }
00547 
00548   }
00549 }//endof ds_mux_handler
00550 
00551 #endif //CONF_DSENSOR_MUX
00552 
00553 
00554 
00555 
00557 //
00558 extern void ds_handler(void);
00559 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00560 __asm__("\n\
00561 .text\n\
00562 .align 1\n\
00563 _ds_handler:\n\
00564    ; r6 saved by ROM\n\
00565 \n\
00566    mov.b @_ds_channel,r6l       ; r6l = current channel\n\
00567 \n\
00568    mov.b @_ds_activation,r6h    ; r6h = activation bitmask\n\
00569    btst r6l,r6h                 ; activate output?\n\
00570    beq ds_noset\n\
00571        bset r6l,@_PORT6:8       ; activate output of last port scanned\n\
00572  ds_noset:\n\
00573         "
00574 #ifdef CONF_DSENSOR_ROTATION
00575         "\n\
00576    mov.b @_ds_rotation,r6h      ; r6h = rotation bitmask\n\
00577    btst r6l,r6h                 ; process rotation sensor?\n\
00578    beq ds_norot\n\
00579 \n\
00580      push r0                    ; save r0..r3\n\
00581      push r1\n\
00582      push r2\n\
00583      push r3                    ; r4..r6 saved by gcc if necessary\n\
00584 \n\
00585      jsr _ds_rotation_handler   ; process rotation sensor\n\
00586 \n\
00587      pop r3\n\
00588      pop r2\n\
00589      pop r1\n\
00590      pop r0\n\
00591  ds_norot:\n\
00592         "
00593 #endif
00594 
00595 #ifdef CONF_DSENSOR_MUX
00596         "\n\
00597    mov.b @_ds_mux,r6h   ; r6h = mux bitmask\n\
00598    btst r6l,r6h                 ; process mux sensor?\n\
00599    beq ds_nomux\n\
00600 \n\
00601      push r0                    ; save r0..r3\n\
00602      push r1\n\
00603      push r2\n\
00604      push r3                    ; r4..r6 saved by gcc if necessary\n\
00605 \n\
00606      jsr _ds_mux_handler        ; process mux sensor\n\
00607 \n\
00608      pop r3\n\
00609      pop r2\n\
00610      pop r1\n\
00611      pop r0\n\
00612  ds_nomux:\n\
00613         "
00614 #endif
00615         "\n\
00616    inc r6l                      ; next channel\n\
00617    and #0x03,r6l                ; limit to 0-3\n\
00618 \n\
00619    mov.b @_ds_activation,r6h    ; r6h = activation bitmask\n\
00620    btst r6l,r6h                 ; activate output?\n\
00621    beq ds_nounset\n\
00622       bclr r6l,@_PORT6:8                ; set output inactive for reading\n\
00623  ds_nounset:\n\
00624 \n\
00625    ; The settle time for reading the value from active sensor start here\n\
00626 \n\
00627    ; moved here for helping timing problems\n\
00628    mov.b r6l,@_ds_channel       ; store next channel\n\
00629 \n\
00630    ; Added a delay loop for sensor settle time\n\
00631 \n\
00632    mov.b #0x04, r6h             ; delay loop\n\
00633 settle:\n\
00634    nop                          ; each nop is a 2 state clock delay\n\
00635    dec.b r6h                    ; 2 states ?\n\
00636    bne settle                   ; 4 states\n\
00637 \n\
00638    ; Total loop delay 32 states (?)\n\
00639 \n\
00640    mov.b @_AD_CSR:8,r6h         ; r6h = A/D CSR\n\
00641    and.b #0x7c,r6h              ; reset scanmode and channel num\n\
00642    or.b  r6l,r6h                ; scan next channel\n\
00643    mov.b r6h,@_AD_CSR:8         ; put r6h back on A/D CSR\n\
00644 \n\
00645    ; The settle time for reading the value from active sensor finish here\n\
00646 \n\
00647    bset #0x5,@_AD_CSR:8         ; go!\n\
00648 \n\
00649    rts\n\
00650 ");
00651 #endif // DOXYGEN_SHOULD_SKIP_THIS
00652 
00653 
00655 
00658 void ds_init(void) {
00659   rom_port6_ddr|=DS_ALL_ACTIVE;         // notify ROM we are using
00660   PORT6_DDR     =rom_port6_ddr;         // PORT6 bit 0..2 as outputs
00661 
00662   ds_activation=0;                      // all sensors passive
00663   ds_channel   =0;                      // start on channel 0
00664 
00665 #ifdef CONF_DSENSOR_ROTATION
00666   ds_rotation  =0;                      // rotation tracking disabled
00667 #endif
00668 
00669 #ifdef CONF_DSENSOR_MUX
00670   ds_mux=0;                             // muxing disabled
00671 #endif
00672 
00673   ad_vector=&ds_handler;                // setup IRQ handler
00674   AD_CR &=~ADCR_EXTERN;
00675   AD_CSR =ADCSR_TIME_266 | ADCSR_GROUP_0 | ADCSR_AN_0  |
00676           ADCSR_ENABLE_IRQ | ADCSR_START;
00677 
00678 #ifdef CONF_CONIO
00679     delay(10);                          // wait for initial A/D
00680 #else
00681 # warning "Rotation initialization might fail."
00682 #endif
00683 }
00684 
00685 
00687 
00689 void ds_shutdown(void) {
00690 
00691   AD_CSR=0x00;
00692   PORT6        &=DS_ALL_PASSIVE;
00693   rom_port6_ddr&=DS_ALL_PASSIVE;
00694   PORT6_DDR     =rom_port6_ddr;
00695 }
00696 
00697 #endif  // CONF_DSENSOR

brickOS is released under the Mozilla Public License.
Original code copyright 1998-2002 by the authors.

Generated on Mon Feb 16 21:02:10 2004 for brickOS Kernel Developer by doxygen 1.3.5