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. |