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

kernel/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 
00129 void ds_rotation_set(volatile unsigned *sensor,int pos) {
00130   if(sensor>=&AD_A && sensor<=&AD_C) {    // catch range violations
00131     unsigned channel=(unsigned) (sensor-&AD_A);
00132     signed char state=ad2state[(*sensor)>>12];
00133 
00134     if(state<0)
00135       state=0;
00136 
00137     rotation_state[channel]=state;
00138     rotation_new_state[channel] = -1;
00139     state_duration[channel]=0;
00140     ds_rotations[channel]=pos;            // reset counter
00141 
00142   }
00143 }
00144 
00146 
00148 void ds_rotation_handler() {
00149   unsigned    channel =ds_channel;
00150   unsigned    raw     =(*((&AD_A)+channel));
00151   signed char newstate=ad2state[raw>>12];
00152 
00153   if (newstate < 0)
00154     return;
00155 
00156   if (newstate == rotation_new_state[channel]) {
00157     if (++state_duration[channel] == 2) {
00158       signed char change = diff2change[newstate - rotation_state[channel] + 3];
00159 
00160       ds_rotations[channel] += change;
00161 
00162 #ifdef CONF_DSENSOR_VELOCITY
00163       {
00164         /* We only take the lowest 16 bits of sys_time.  We have to be
00165          * a bit careful with wraparounds, but this is handled here.
00166          */
00167         unsigned int time = (unsigned int) sys_time;
00168         if (change != rotation_dir[channel]) {
00169           rotation_dir[channel] = change;
00170           ds_velocities[channel] = 0;
00171           last_rotation[channel] = time;
00172           next_rotation[channel] = time + 1000;
00173         } else {
00174           if (time == last_rotation[channel])
00175             ds_velocities[channel] = 1000 * change;
00176           else {
00177             unsigned int time_diff = (time - last_rotation[channel]);
00178             if (time_diff > 1000) {
00179               rotation_dir[channel] = 0;
00180               ds_velocities[channel] = 0;
00181             } else {
00182               int speed = 1000 / time_diff;
00183               ds_velocities[channel] = change > 0 ? speed : -speed;
00184               last_rotation[channel] = time;
00185               next_rotation[channel] = time + time_diff * 3 / 2;
00186             }
00187           }
00188         }
00189       }
00190 #endif
00191 
00192       rotation_state[channel] = newstate;
00193       rotation_new_state[channel] = -1;
00194     }
00195   } else if (newstate != rotation_state[channel]) {
00196     rotation_new_state[channel] = newstate;
00197     state_duration[channel] = 1;
00198 #ifdef CONF_DSENSOR_VELOCITY
00199   } else {
00200     /* No rotation change, check if velocity measure timeouts. */
00201     unsigned int time = (unsigned int) sys_time;
00202     if (rotation_dir[channel] &&  
00203         ((signed int) (time - next_rotation[channel])) >= 0) {
00204       unsigned int time_diff = (time - last_rotation[channel]);
00205       if (time_diff > 1000) {
00206         rotation_dir[channel] = 0;
00207         ds_velocities[channel] = 0;
00208       } else {  
00209         int speed = 1000 / time_diff;
00210         ds_velocities[channel] = rotation_dir[channel] > 0 ? speed : -speed;
00211         next_rotation[channel] = time + time_diff / 2;
00212       }
00213     }
00214 #endif
00215   }
00216 
00217 }
00218 #endif // CONF_DSENSOR_ROTATION
00219 
00220 #ifdef CONF_DSENSOR_MUX
00221 unsigned char ds_mux;   
00222 
00223 volatile int ds_muxs[3][3];     
00224 
00225 
00226 //width of each mux pulse
00227 #define DS_MUX_PULSE_TM_MS 10
00228 
00229 
00230 
00231 typedef struct {
00232   unsigned long nextTm;  //timestamp for next pulse
00233   char remainingEdges;    //edges left in pulse train
00234   char channel; //current mux sub channel (0,1,2)
00235   unsigned int attached[3];//what channels are sensors attached to
00236                             //this also defines the number of ms
00237                             //to wait before reading the value
00238   
00239   enum {ds_mux_prepRead,
00240         ds_mux_read, 
00241         ds_mux_pulse_low, 
00242         ds_mux_pulse_high} action; //specify next action
00243 } ds_mux_data_t;
00244 
00245 ds_mux_data_t ds_mux_data[3]; //data on mux
00246 
00247 #endif //CONF_DSENSOR_MUX
00248 
00249 
00250 
00251 static inline void ds_power_on(unsigned channel) {
00252   switch(channel) {
00253   case 0:
00254     bit_set(&PORT6,0);
00255     break;
00256   case 1:
00257     bit_set(&PORT6,1);
00258     break;
00259   case 2:
00260     bit_set(&PORT6,2);
00261     break;
00262   default:
00263     //bad
00264     break;
00265   }
00266 }//endof ds_power_on
00267 
00268 static inline void ds_power_off(unsigned channel) {
00269   switch(channel) {
00270   case 0:
00271     bit_clear(&PORT6,0);
00272     break;
00273   case 1:
00274     bit_clear(&PORT6,1);
00275     break;
00276   case 2:
00277     bit_clear(&PORT6,2);
00278     break;
00279   default:
00280     //bad
00281     break;
00282   }
00283 }//endof ds_power_off
00284 
00285 #ifdef CONF_DSENSOR_MUX
00286 
00287 
00289 void ds_mux_on(volatile unsigned *sensor,
00290                unsigned int ch1,
00291                unsigned int ch2,
00292                unsigned int ch3) {
00293   unsigned char i,j;
00294   ds_passive(sensor);//powered, but not active in legOS sense
00295 
00296 
00297   if(ch1==0 &&
00298      ch2==0 &&
00299      ch3==0) {
00300     //umm this is useless
00301     //avoid endless cycling
00302     ds_mux_off(sensor);
00303     return;
00304   }
00305 
00306   if (sensor == &SENSOR_3) {
00307     i=0;
00308   } else if (sensor == &SENSOR_2) {
00309     i=1;
00310   } else if (sensor == &SENSOR_1) {
00311     i=2;
00312   } else {
00313     //bad
00314     return;
00315   }
00316 
00317   
00318   ds_mux_data[i].attached[0]=ch1;
00319   ds_mux_data[i].attached[1]=ch2;
00320   ds_mux_data[i].attached[2]=ch3;
00321   
00322   //add extended time based on the channel
00323   //this is required by the mux
00324   //the user supplies extra time based on the
00325   //type of sensor they hook up
00326   //these defaults give enough time to read
00327   //a light sensor and should be ok for most
00328   //sensors
00329   if(ch1)
00330     ds_mux_data[i].attached[0]+=160;
00331   if(ch2)
00332     ds_mux_data[i].attached[1]+=135;
00333   if(ch3)
00334     ds_mux_data[i].attached[2]+=25;
00335 
00336 
00337 
00338 
00339   //check if we're just adjusting the ports
00340   //if so we can return here
00341   if(i==0 && ds_mux&1)
00342     return;
00343   if(i==1 && ds_mux&2)
00344     return;
00345   if(i==2 && ds_mux&4)
00346     return;
00347 
00348   //starting up mux
00349 
00350   //power up
00351   ds_power_on(i);
00352   
00353   //schedule first event
00354   //find first attached sensor
00355   for(j=0;j<3 && ds_mux_data[i].attached[j]==0;j++);
00356     
00357   ds_mux_data[i].channel=j;
00358   ds_mux_data[i].remainingEdges=((j+1)*2);
00359   ds_mux_data[i].action=ds_mux_pulse_low;
00360   ds_mux_data[i].nextTm=sys_time+DS_MUX_PULSE_TM_MS;
00361 
00362   if (sensor == &SENSOR_3) {
00363     bit_set(&ds_mux, 0);
00364   } else if (sensor == &SENSOR_2) {
00365     bit_set(&ds_mux, 1);
00366   } else if (sensor == &SENSOR_1) {
00367     bit_set(&ds_mux, 2);
00368   } else {
00369     //bad
00370     return;
00371   }
00372 
00373 }//endof ds_mux_on
00374 
00375 
00376 
00377 void ds_mux_handler() {
00378   unsigned sen=ds_channel;
00379 
00380 
00381   if(ds_mux_data[sen].nextTm <= sys_time) {
00382     //we've reached our next scheduled step
00383     //lcd_int(sys_time-ds_mux_data[sen].nextTm);
00384     switch(ds_mux_data[sen].action) {
00385     case ds_mux_prepRead:
00386       ds_power_off(sen);//power down for read
00387       ds_mux_data[sen].action=ds_mux_read;
00388       ds_mux_data[sen].nextTm=sys_time;//do it ASAP, but not now
00389       break;
00390     case ds_mux_read:
00391       //read data
00392       switch(sen) {
00393       case 0:
00394         ds_muxs[sen][(int)ds_mux_data[sen].channel]=SENSOR_3;
00395         break;
00396       case 1:
00397         ds_muxs[sen][(int)ds_mux_data[sen].channel]=SENSOR_2;
00398         break;
00399       case 2:
00400         ds_muxs[sen][(int)ds_mux_data[sen].channel]=SENSOR_1;
00401         break;
00402       default:
00403         //bad
00404       }
00405 
00406  
00407       //change channel
00408       do {
00409         ds_mux_data[sen].channel++;
00410         if(ds_mux_data[sen].channel>2/*max chan*/) {
00411           ds_mux_data[sen].channel=0;
00412         }
00413         //make sure selected channel is marked attached
00414         //don't worry about an endless loop ds_mux_on makes
00415         //sure at least one channel is attached
00416       } while(
00417               (ds_mux_data[sen].attached
00418                [(int)ds_mux_data[sen].channel])==0);
00419       
00420     
00421       //use this low pulse as the first low pulse of next train
00422 
00423       ds_mux_data[sen].remainingEdges=
00424         ((ds_mux_data[sen].channel+1)*2)-1;
00425 
00426       //schedule next high pulse
00427       ds_mux_data[sen].action=ds_mux_pulse_high;
00428       ds_mux_data[sen].nextTm=sys_time+DS_MUX_PULSE_TM_MS;
00429       break;
00430     case ds_mux_pulse_low:
00431       //go low
00432       ds_power_off(sen);
00433       //schedule next high pulse
00434       ds_mux_data[sen].nextTm=sys_time+DS_MUX_PULSE_TM_MS;
00435       ds_mux_data[sen].remainingEdges--;  
00436       ds_mux_data[sen].action=ds_mux_pulse_high;
00437       break;
00438     case ds_mux_pulse_high:
00439       //go high
00440       ds_power_on(sen);
00441       ds_mux_data[sen].remainingEdges--;      
00442      
00443       if(ds_mux_data[sen].remainingEdges==0) {
00444         //done with train
00445         //schedule prepRead
00446         ds_mux_data[sen].action=ds_mux_prepRead;
00447 
00448         //schedule enough time for the mux to make the switch
00449         //this is scaled because the timeout the mux uses starts
00450         //when the first pulse comes in, it is around 70ms, so
00451         //when switching to sensor 1 we must want an additional
00452         //amount of time before it mux reacts, we wait less for 2
00453         //and not at all for 3
00454         //then we wait a little bit before reading the sensor
00455         //this give the sensor time to power up
00456         ds_mux_data[sen].nextTm=sys_time+
00457           ds_mux_data[sen].attached[(int)ds_mux_data[sen].channel];
00458         //lcd_int(ds_mux_data[sen].channel+1);
00459 
00460         break;
00461       } else {
00462         //schedule next low pulse
00463         ds_mux_data[sen].action=ds_mux_pulse_low;
00464         ds_mux_data[sen].nextTm=sys_time+DS_MUX_PULSE_TM_MS;
00465       }      
00466       break;
00467     default:
00468       //bad
00469     }
00470 
00471   }
00472 }//endof ds_mux_handler
00473 
00474 #endif //CONF_DSENSOR_MUX
00475 
00476 
00477 
00478 
00480 //
00481 extern void ds_handler(void);
00482 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00483 __asm__("\n\
00484 .text\n\
00485 .align 1\n\
00486 _ds_handler:\n\
00487    ; r6 saved by ROM\n\
00488 \n\
00489    mov.b @_ds_channel,r6l       ; r6l = current channel\n\
00490 \n\
00491    mov.b @_ds_activation,r6h    ; r6h = activation bitmask\n\
00492    btst r6l,r6h                 ; activate output?\n\
00493    beq ds_noset\n\
00494        bset r6l,@_PORT6:8       ; activate output of last port scanned\n\
00495  ds_noset:\n\
00496         "
00497 #ifdef CONF_DSENSOR_ROTATION
00498         "\n\
00499    mov.b @_ds_rotation,r6h      ; r6h = rotation bitmask\n\
00500    btst r6l,r6h                 ; process rotation sensor?\n\
00501    beq ds_norot\n\
00502 \n\
00503      push r0                    ; save r0..r3\n\
00504      push r1\n\
00505      push r2\n\
00506      push r3                    ; r4..r6 saved by gcc if necessary\n\
00507 \n\
00508      jsr _ds_rotation_handler   ; process rotation sensor\n\
00509 \n\
00510      pop r3\n\
00511      pop r2\n\
00512      pop r1\n\
00513      pop r0\n\
00514  ds_norot:\n\
00515         "
00516 #endif
00517 
00518 #ifdef CONF_DSENSOR_MUX
00519         "\n\
00520    mov.b @_ds_mux,r6h   ; r6h = mux bitmask\n\
00521    btst r6l,r6h                 ; process mux sensor?\n\
00522    beq ds_nomux\n\
00523 \n\
00524      push r0                    ; save r0..r3\n\
00525      push r1\n\
00526      push r2\n\
00527      push r3                    ; r4..r6 saved by gcc if necessary\n\
00528 \n\
00529      jsr _ds_mux_handler        ; process mux sensor\n\
00530 \n\
00531      pop r3\n\
00532      pop r2\n\
00533      pop r1\n\
00534      pop r0\n\
00535  ds_nomux:\n\
00536         "
00537 #endif
00538         "\n\
00539    inc r6l                      ; next channel\n\
00540    and #0x03,r6l                ; limit to 0-3\n\
00541 \n\
00542    mov.b @_ds_activation,r6h    ; r6h = activation bitmask\n\
00543    btst r6l,r6h                 ; activate output?\n\
00544    beq ds_nounset\n\
00545       bclr r6l,@_PORT6:8                ; set output inactive for reading\n\
00546  ds_nounset:\n\
00547 \n\
00548    ; The settle time for reading the value from active sensor start here\n\
00549 \n\
00550    ; moved here for helping timing problems\n\
00551    mov.b r6l,@_ds_channel       ; store next channel\n\
00552 \n\
00553    ; Added a delay loop for sensor settle time\n\
00554 \n\
00555    mov.b #0x04, r6h             ; delay loop\n\
00556 settle:\n\
00557    nop                          ; each nop is a 2 state clock delay\n\
00558    dec.b r6h                    ; 2 states ?\n\
00559    bne settle                   ; 4 states\n\
00560 \n\
00561    ; Total loop delay 32 states (?)\n\
00562 \n\
00563    mov.b @_AD_CSR:8,r6h         ; r6h = A/D CSR\n\
00564    and.b #0x7c,r6h              ; reset scanmode and channel num\n\
00565    or.b  r6l,r6h                ; scan next channel\n\
00566    mov.b r6h,@_AD_CSR:8         ; put r6h back on A/D CSR\n\
00567 \n\
00568    ; The settle time for reading the value from active sensor finish here\n\
00569 \n\
00570    bset #0x5,@_AD_CSR:8         ; go!\n\
00571 \n\
00572    rts\n\
00573 ");
00574 #endif // DOXYGEN_SHOULD_SKIP_THIS
00575 
00576 
00578 
00581 void ds_init(void) {
00582   rom_port6_ddr|=DS_ALL_ACTIVE;         // notify ROM we are using
00583   PORT6_DDR     =rom_port6_ddr;         // PORT6 bit 0..2 as outputs
00584 
00585   ds_activation=0;                      // all sensors passive
00586   ds_channel   =0;                      // start on channel 0
00587 
00588 #ifdef CONF_DSENSOR_ROTATION
00589   ds_rotation  =0;                      // rotation tracking disabled
00590 #endif
00591 
00592 #ifdef CONF_DSENSOR_MUX
00593   ds_mux=0;                             // muxing disabled
00594 #endif
00595 
00596   ad_vector=&ds_handler;                // setup IRQ handler
00597   AD_CR &=~ADCR_EXTERN;
00598   AD_CSR =ADCSR_TIME_266 | ADCSR_GROUP_0 | ADCSR_AN_0  |
00599           ADCSR_ENABLE_IRQ | ADCSR_START;
00600 
00601 #ifdef CONF_CONIO
00602     delay(10);                          // wait for initial A/D
00603 #else
00604 # warning "Rotation initialization might fail."
00605 #endif
00606 }
00607 
00608 
00610 
00612 void ds_shutdown(void) {
00613 
00614   AD_CSR=0x00;
00615   PORT6        &=DS_ALL_PASSIVE;
00616   rom_port6_ddr&=DS_ALL_PASSIVE;
00617   PORT6_DDR     =rom_port6_ddr;
00618 }
00619 
00620 #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