00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 #include <string.h>
00091
00092 #include <dev/irqreg.h>
00093
00094 #include <sys/event.h>
00095 #include <sys/atom.h>
00096 #include <sys/timer.h>
00097 #include <sys/thread.h>
00098 #include <sys/heap.h>
00099
00100 #include <dev/twif.h>
00101
00102 #ifdef __AVR_ENHANCED__
00103
00104 static volatile u_char tw_if_bsy;
00105
00106 HANDLE tw_mm_mutex;
00107 HANDLE tw_mm_que;
00108 HANDLE tw_sr_que;
00109 HANDLE tw_st_que;
00110
00111 static u_char tw_mm_sla;
00112 static volatile u_char tw_mm_err;
00113 static u_char tw_mm_error;
00114
00115 static CONST u_char *tw_mt_buf;
00116 static volatile u_short tw_mt_len;
00117 static volatile u_short tw_mt_idx;
00118
00119 static u_char *tw_mr_buf;
00120 static volatile u_short tw_mr_siz;
00121 static volatile u_short tw_mr_idx;
00122
00123 static volatile u_char tw_sm_sla;
00124 static volatile u_char tw_sm_err;
00125 static u_char tw_sm_error;
00126
00127 static u_char *tw_st_buf;
00128 static volatile u_short tw_st_len;
00129 static volatile u_short tw_st_idx;
00130
00131 static u_char *tw_sr_buf;
00132 static volatile u_short tw_sr_siz;
00133 static volatile u_short tw_sr_idx;
00134
00135
00136
00137
00138
00139
00140 #define TWGO (_BV(TWINT) | _BV(TWEN) | _BV(TWIE))
00141
00142
00143
00144
00145 static void TwInterrupt(void *arg)
00146 {
00147 u_char twsr;
00148 register u_char twcr = inb(TWCR);
00149
00150
00151
00152
00153 twsr = inb(TWSR) & 0xF8;
00154 switch (twsr) {
00155
00156
00157
00158
00159
00160 case TW_START:
00161 case TW_REP_START:
00162
00163 tw_if_bsy = 1;
00164 tw_mt_idx = 0;
00165 tw_mr_idx = 0;
00166
00167
00168
00169
00170
00171 if (tw_mt_len) {
00172 outb(TWDR, tw_mm_sla);
00173 }
00174
00175
00176
00177
00178
00179 else {
00180 outb(TWDR, tw_mm_sla | 1);
00181 }
00182 outb(TWCR, TWGO | (twcr & _BV(TWEA)));
00183 break;
00184
00185
00186
00187
00188
00189 case TW_MT_SLA_ACK:
00190 case TW_MT_DATA_ACK:
00191
00192
00193
00194
00195 if (tw_mt_idx < tw_mt_len) {
00196 outb(TWDR, tw_mt_buf[tw_mt_idx]);
00197
00198 tw_mt_idx++;
00199 outb(TWCR, TWGO | (twcr & _BV(TWEA)));
00200 break;
00201 }
00202
00203
00204
00205
00206
00207 tw_mt_len = 0;
00208 if (tw_mr_siz) {
00209 outb(TWCR, TWGO | (twcr & _BV(TWEA)) | _BV(TWSTA));
00210 break;
00211 }
00212
00213
00214
00215
00216
00217
00218 case TW_MT_SLA_NACK:
00219 case TW_MT_DATA_NACK:
00220 case TW_MR_SLA_NACK:
00221
00222 if (twsr == TW_MT_SLA_NACK || twsr == TW_MR_SLA_NACK) {
00223 tw_mm_err = TWERR_SLA_NACK;
00224 tw_mt_len = 0;
00225 tw_mr_siz = 0;
00226 }
00227
00228
00229 NutEventPostFromIrq(&tw_mm_que);
00230
00231
00232
00233
00234
00235 if(tw_sr_siz) {
00236 outb(TWCR, TWGO | _BV(TWEA) | _BV(TWSTO));
00237 }
00238 else {
00239 outb(TWCR, TWGO | _BV(TWSTO));
00240 }
00241
00242
00243 tw_if_bsy = 0;
00244 break;
00245
00246
00247
00248
00249 case TW_MT_ARB_LOST:
00250
00251
00252
00253
00254 sbi(TWCR, TWSTA);
00255
00256 tw_if_bsy = 0;
00257 break;
00258
00259
00260
00261
00262 case TW_MR_DATA_ACK:
00263
00264
00265
00266 tw_mr_buf[tw_mr_idx] = inb(TWDR);
00267
00268 tw_mr_idx++;
00269
00270
00271
00272
00273 case TW_MR_SLA_ACK:
00274
00275
00276
00277 if (tw_mr_idx + 1 < tw_mr_siz) {
00278 outb(TWCR, TWGO | _BV(TWEA));
00279 }
00280 else {
00281 outb(TWCR, TWGO);
00282 }
00283 break;
00284
00285
00286
00287
00288 case TW_MR_DATA_NACK:
00289
00290
00291
00292 tw_mr_buf[tw_mr_idx] = inb(TWDR);
00293
00294 tw_mr_idx++;
00295 tw_mr_siz = 0;
00296
00297
00298 NutEventPostFromIrq(&tw_mm_que);
00299
00300
00301
00302
00303
00304 if(tw_sr_siz) {
00305 outb(TWCR, TWGO | _BV(TWEA) | _BV(TWSTO));
00306 }
00307 else {
00308 outb(TWCR, TWGO | _BV(TWSTO));
00309 }
00310
00311
00312 tw_if_bsy = 0;
00313 break;
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 case TW_SR_SLA_ACK:
00324 case TW_SR_ARB_LOST_SLA_ACK:
00325 case TW_SR_GCALL_ACK:
00326 case TW_SR_ARB_LOST_GCALL_ACK:
00327
00328
00329
00330
00331
00332 if (tw_sr_siz) {
00333
00334 tw_if_bsy = 1;
00335
00336 tw_sm_sla = inb(TWDR);
00337 outb(TWCR, TWGO | _BV(TWEA));
00338 tw_sr_idx = 0;
00339 }
00340
00341
00342
00343
00344 else {
00345 outb(TWCR, TWGO);
00346 }
00347 break;
00348
00349
00350
00351
00352
00353
00354 case TW_SR_DATA_ACK:
00355 case TW_SR_GCALL_DATA_ACK:
00356
00357
00358
00359 if (tw_sr_idx < tw_sr_siz) {
00360 tw_sr_buf[tw_sr_idx] = inb(TWDR);
00361
00362 tw_sr_idx++;
00363 }
00364 else {
00365 tw_sr_siz = 0;
00366 }
00367
00368
00369
00370
00371
00372 if (tw_sr_siz) {
00373 outb(TWCR, TWGO | _BV(TWEA));
00374 break;
00375 }
00376
00377
00378
00379
00380
00381
00382 case TW_SR_DATA_NACK:
00383 case TW_SR_GCALL_DATA_NACK:
00384
00385
00386
00387 if (tw_mt_len || tw_mr_siz) {
00388 outb(TWCR, inb(TWCR) | _BV(TWEA) | _BV(TWSTA));
00389 }
00390 else {
00391 outb(TWCR, inb(TWCR) | _BV(TWEA));
00392 }
00393 break;
00394
00395
00396
00397
00398 case TW_SR_STOP:
00399
00400
00401
00402
00403
00404
00405 if (tw_sr_que == 0 || tw_sm_err) {
00406
00407
00408
00409
00410
00411
00412 if (tw_mt_len || tw_mr_siz) {
00413 outb(TWCR, TWGO | _BV(TWSTA));
00414 }
00415 else {
00416 outb(TWCR, TWGO);
00417 }
00418 tw_if_bsy = 0;
00419 }
00420 else {
00421 NutEventPostFromIrq(&tw_sr_que);
00422 tw_sr_siz = 0;
00423 outb(TWCR, twcr & ~(_BV(TWINT) | _BV(TWIE)));
00424 }
00425 break;
00426
00427
00428
00429
00430
00431
00432 case TW_ST_SLA_ACK:
00433 case TW_ST_ARB_LOST_SLA_ACK:
00434
00435 tw_if_bsy = 1;
00436
00437 tw_st_idx = 0;
00438
00439
00440
00441
00442 case TW_ST_DATA_ACK:
00443
00444
00445
00446
00447 if (tw_st_idx < tw_st_len) {
00448 outb(TWDR, tw_st_buf[tw_st_idx]);
00449
00450
00451 ++tw_st_idx;
00452 if (tw_st_idx < tw_st_len) {
00453 outb(TWCR, TWGO | _BV(TWEA));
00454 }
00455 else {
00456 tw_st_len = 0;
00457 outb(TWCR, TWGO);
00458 }
00459 break;
00460 }
00461
00462
00463 outb(TWDR, 0);
00464 outb(TWCR, TWGO);
00465 break;
00466
00467
00468
00469
00470
00471 case TW_ST_DATA_NACK:
00472 case TW_ST_LAST_DATA:
00473 NutEventPostFromIrq(&tw_st_que);
00474
00475
00476 if (tw_mt_len || tw_mr_siz) {
00477 outb(TWCR, TWGO | _BV(TWSTA) | _BV(TWEA));
00478 }
00479
00480 else {
00481 outb(TWCR, TWGO | _BV(TWEA));
00482 }
00483 tw_if_bsy = 0;
00484 break;
00485
00486
00487
00488
00489 case TW_BUS_ERROR:
00490 outb(TWCR, inb(TWCR) | _BV(TWSTO));
00491 #if 1
00492 tw_if_bsy = 0;
00493 tw_mm_err = TWERR_BUS;
00494 tw_sm_err = TWERR_BUS;
00495 NutEventPostFromIrq(&tw_sr_que);
00496 NutEventPostFromIrq(&tw_st_que);
00497 NutEventPostFromIrq(&tw_mm_que);
00498 #endif
00499 break;
00500 }
00501 }
00502
00503 #endif
00504
00532 int TwMasterTransact(u_char sla, CONST void *txdata, u_short txlen, void *rxdata, u_short rxsiz, u_long tmo)
00533 {
00534 int rc = -1;
00535
00536 #ifdef __AVR_ENHANCED__
00537
00538 if(NutEventWait(&tw_mm_mutex, 500)) {
00539 tw_mm_err = TWERR_IF_LOCKED;
00540 NutEventPost(&tw_mm_mutex);
00541 return -1;
00542 }
00543
00544 while(tw_if_bsy) {
00545 NutSleep(63);
00546 }
00547 NutEnterCritical();
00548
00549
00550
00551 tw_mm_sla = sla << 1;
00552 tw_mm_err = 0;
00553 tw_mt_len = txlen;
00554 tw_mt_buf = txdata;
00555 tw_mr_siz = rxsiz;
00556 tw_mr_buf = rxdata;
00557
00558
00559
00560
00561
00562
00563 if(tw_if_bsy == 0) {
00564 u_char twcr = inb(TWCR);
00565 u_char twsr = inb(TWSR);
00566 if((twsr & 0xF8) == TW_NO_INFO) {
00567 if(tw_sr_siz) {
00568 outb(TWCR, _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWSTA) | (twcr & _BV(TWSTO)));
00569 }
00570 else {
00571 outb(TWCR, _BV(TWEN) | _BV(TWIE) | _BV(TWSTA) | (twcr & _BV(TWSTO)));
00572 }
00573 }
00574 }
00575
00576
00577
00578 if (tw_mm_que == SIGNALED) {
00579 tw_mm_que = 0;
00580 }
00581 NutExitCritical();
00582
00583
00584
00585
00586 rc = -1;
00587 if (NutEventWait(&tw_mm_que, tmo)) {
00588 tw_mm_error = TWERR_TIMEOUT;
00589 } else {
00590 NutEnterCritical();
00591 if (tw_mm_err) {
00592 tw_mm_error = tw_mm_err;
00593 } else {
00594 rc = tw_mr_idx;
00595 }
00596 NutExitCritical();
00597 }
00598
00599
00600
00601
00602 NutEventPost(&tw_mm_mutex);
00603
00604 #endif
00605 return rc;
00606 }
00607
00617 int TwMasterError(void)
00618 {
00619 #ifndef __AVR_ENHANCED__
00620 return -1;
00621 #else
00622 int rc = (int) tw_mm_error;
00623 tw_mm_error = 0;
00624 return rc;
00625 #endif
00626 }
00627
00650 int TwSlaveListen(u_char * sla, void *rxdata, u_short rxsiz, u_long tmo)
00651 {
00652 #ifndef __AVR_ENHANCED__
00653 return -1;
00654 #else
00655 int rc = -1;
00656
00657 NutEnterCritical();
00658
00659
00660 tw_sm_err = 0;
00661 tw_sr_siz = rxsiz;
00662 tw_sr_buf = rxdata;
00663
00664
00665
00666
00667
00668 if(tw_if_bsy == 0) {
00669 u_char twsr = inb(TWSR);
00670 if((twsr & 0xF8) == TW_NO_INFO) {
00671 if(tw_mt_len || tw_mr_siz)
00672 outb(TWCR, _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA));
00673 else
00674 outb(TWCR, _BV(TWEA) | _BV(TWEN) | _BV(TWIE));
00675 }
00676 }
00677
00678
00679
00680 if (tw_sr_que == SIGNALED) {
00681 tw_sr_que = 0;
00682 }
00683
00684 NutExitCritical();
00685
00686
00687 if (NutEventWait(&tw_sr_que, tmo)) {
00688 NutEnterCritical();
00689 tw_sm_err = TWERR_TIMEOUT;
00690 tw_sr_siz = 0;
00691 NutExitCritical();
00692 }
00693
00694
00695
00696
00697
00698
00699 if(tw_sm_err == 0) {
00700 rc = tw_sr_idx;
00701 *sla = tw_sm_sla;
00702 }
00703 return rc;
00704 #endif
00705 }
00706
00724 int TwSlaveRespond(void *txdata, u_short txlen, u_long tmo)
00725 {
00726 int rc = -1;
00727 #ifdef __AVR_ENHANCED__
00728
00729
00730 tw_st_buf = txdata;
00731 tw_st_len = txlen;
00732
00733
00734
00735
00736 if (txlen) {
00737 NutEnterCritical();
00738
00739
00740 if (tw_st_que == SIGNALED) {
00741 tw_st_que = 0;
00742 }
00743
00744
00745 outb(TWCR, TWGO | _BV(TWEA));
00746
00747 NutExitCritical();
00748 if (NutEventWait(&tw_st_que, tmo)) {
00749 tw_sm_err = TWERR_TIMEOUT;
00750 }
00751
00752 NutEnterCritical();
00753 tw_st_len = 0;
00754 if (tw_sm_err) {
00755 tw_sm_error = tw_sm_err;
00756 } else {
00757 rc = tw_st_idx;
00758 }
00759 NutExitCritical();
00760 }
00761
00762
00763
00764
00765 else {
00766 u_char twcr;
00767 u_char twsr;
00768 rc = 0;
00769
00770
00771 NutEnterCritical();
00772 twcr = inb(TWCR);
00773 twsr = inb(TWSR);
00774
00775 if (tw_mt_len || tw_mr_siz) {
00776 outb(TWCR, TWGO | _BV(TWSTA));
00777 }
00778
00779 else {
00780 tw_if_bsy = 0;
00781 outb(TWCR, TWGO);
00782 }
00783
00784 NutExitCritical();
00785 }
00786 #endif
00787 return rc;
00788 }
00789
00799 int TwSlaveError(void)
00800 {
00801 #ifndef __AVR_ENHANCED__
00802 return -1;
00803 #else
00804 int rc = (int) tw_sm_error;
00805 tw_sm_error = 0;
00806 return rc;
00807 #endif
00808 }
00809
00827 int TwIOCtl(int req, void *conf)
00828 {
00829 #ifndef __AVR_ENHANCED__
00830 return -1;
00831 #else
00832 int rc = 0;
00833 u_long lval;
00834
00835 switch (req) {
00836 case TWI_SETSLAVEADDRESS:
00837 TWAR = (*((u_char *) conf) << 1) | 1;
00838 break;
00839 case TWI_GETSLAVEADDRESS:
00840 *((u_char *) conf) = TWAR;
00841 break;
00842
00843 case TWI_SETSPEED:
00844 lval = ((2UL * NutGetCpuClock() / (*((u_long *) conf)) + 1UL) / 2UL - 16UL) / 2UL;
00845 if (lval > 1020UL) {
00846 lval /= 16UL;
00847 sbi(TWSR, TWPS1);
00848 } else {
00849 cbi(TWSR, TWPS1);
00850 }
00851 if (lval > 255UL) {
00852 lval /= 4UL;
00853 sbi(TWSR, TWPS0);
00854 } else {
00855 cbi(TWSR, TWPS0);
00856 }
00857 if (lval > 9UL && lval < 256UL) {
00858 outb(TWBR, (u_char) lval);
00859 } else {
00860 rc = -1;
00861 }
00862 break;
00863 case TWI_GETSPEED:
00864 lval = 2UL;
00865 if (bit_is_set(TWSR, TWPS0)) {
00866 lval *= 4UL;
00867 }
00868 if (bit_is_set(TWSR, TWPS1)) {
00869 lval *= 16UL;
00870 }
00871 *((u_long *) conf) = NutGetCpuClock() / (16UL + lval * (u_long) inb(TWBR));
00872 break;
00873
00874 case TWI_GETSTATUS:
00875 break;
00876 case TWI_SETSTATUS:
00877 break;
00878
00879 default:
00880 rc = -1;
00881 break;
00882 }
00883 return rc;
00884 #endif
00885 }
00886
00899 int TwInit(u_char sla)
00900 {
00901 #ifndef __AVR_ENHANCED__
00902 return -1;
00903 #else
00904 u_long speed = 2400;
00905
00906 if (NutRegisterIrqHandler(&sig_2WIRE_SERIAL, TwInterrupt, 0)) {
00907 return -1;
00908 }
00909
00910
00911
00912
00913
00914 outb(TWAR, (sla << 1) | 1);
00915 TwIOCtl(TWI_SETSPEED, &speed);
00916 outb(TWCR, _BV(TWINT));
00917 outb(TWCR, _BV(TWEN) | _BV(TWIE));
00918
00919
00920
00921
00922 NutEventPost(&tw_mm_mutex);
00923
00924 return 0;
00925 #endif
00926 }