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