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