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 #include <compiler.h>
00044 #include <string.h>
00045 #include <dev/irqreg.h>
00046 #include <sys/atom.h>
00047 #include <sys/event.h>
00048 #include <sys/thread.h>
00049 #include <sys/device.h>
00050 #include <arch/timer.h>
00051 #include <dev/irblast.h>
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 typedef struct _IRBLASTDCB IRBLASTDCB;
00085 struct _IRBLASTDCB {
00086
00087
00088
00089 HANDLE dcb_tx_rdy;
00090
00091
00092 volatile u_char if_tx_idx;
00093
00094 u_char if_wr_idx;
00095
00096 volatile u_char if_tx_act;
00097
00098 u_short if_tx_buf[256];
00099 };
00100
00101 static IRBLASTDCB dcb_pwm0;
00102 static NUTFILE file;
00103
00104
00112 u_char IrblastFreq2Ocr(u_char freqKHz)
00113 {
00114 u_long div;
00115 u_char ocr = 0;
00116
00117 if ((freqKHz >= 30) && (freqKHz <= 50)) {
00118
00119 div = 2000UL * (u_long) freqKHz;
00120 ocr = (u_char) ((NutGetCpuClock() / div) & 0x000000ff) - 1;
00121 }
00122 return ocr;
00123 }
00124
00137 int IrblastPeriod2Ocr(u_char freqKHz, int entries, u_short * pCode)
00138 {
00139 u_long div, sClk, freq;
00140 int i = -1;
00141
00142 if ((freqKHz < 30) && (freqKHz > 50)) {
00143 freqKHz = 100;
00144 }
00145
00146
00147 sClk = NutGetCpuClock() / 10UL;
00148 freq = 800UL * (u_long) (freqKHz);
00149
00150 for (i = 0; i < entries; ++i) {
00151 if ((pCode[i] == 0) || (pCode[i] > 1000)) {
00152 return -1;
00153 }
00154 div = sClk * (u_long) pCode[i];
00155 div = div / freq;
00156 pCode[i] = (u_int) (div & 0x0000ffff) - 1;
00157 }
00158 return i;
00159 }
00160
00161
00170 static void IrblastOutComp1CInt(void *arg)
00171 {
00172 NUTDEVICE *dev = (NUTDEVICE *) arg;
00173 IRBLASTDCB *dcb = dev->dev_dcb;
00174
00175 if (dcb->if_tx_idx != dcb->if_wr_idx) {
00176
00177 OCR1A = dcb->if_tx_buf[dcb->if_tx_idx];
00178 OCR1C = dcb->if_tx_buf[dcb->if_tx_idx];
00179 ++(dcb->if_tx_idx);
00180 } else {
00181 dcb->if_tx_act = 0;
00182
00183
00184 TIMSK &= ~_BV(OCIE1C);
00185
00186 TCCR1B &= ~_BV(CS11);
00187
00188 TCCR1A &= ~_BV(COM1C0);
00189 TCCR1A |= _BV(COM1C1);
00190
00191 TCCR1C = _BV(FOC1C);
00192
00193 NutEventPostFromIrq(&dcb->dcb_tx_rdy);
00194 }
00195 }
00196
00197
00212 static int IrblastOutput(NUTDEVICE * dev)
00213 {
00214 IRBLASTDCB *dcb = dev->dev_dcb;
00215
00216 if ((dcb->if_tx_act == 0) && (dcb->if_tx_idx != dcb->if_wr_idx)) {
00217 dcb->if_tx_act = 1;
00218
00219 TCCR1A &= ~_BV(COM1C1);
00220 TCCR1A |= _BV(COM1C0);
00221
00222 TCCR1C = _BV(FOC1C);
00223
00224
00225 TCNT1 = 0;
00226
00227
00228 OCR1A = dcb->if_tx_buf[dcb->if_tx_idx];
00229 OCR1C = dcb->if_tx_buf[dcb->if_tx_idx];
00230
00231 ++(dcb->if_tx_idx);
00232
00233
00234 ETIMSK |= _BV(OCIE1C);
00235
00236 TCCR1B |= _BV(CS11);
00237 }
00238 return 0;
00239 }
00240
00241
00252 static int IrblastFlush(NUTDEVICE * dev)
00253 {
00254 IRBLASTDCB *dcb = dev->dev_dcb;
00255
00256
00257 IrblastOutput(dev);
00258
00259
00260 while (dcb->if_tx_idx != dcb->if_wr_idx) {
00261 NutEventWaitNext(&dcb->dcb_tx_rdy, 100);
00262 }
00263
00264
00265 ETIMSK &= ~_BV(OCIE1C);
00266
00267 TCCR1B &= ~_BV(CS11);
00268
00269 TCCR1A &= ~_BV(COM1C0);
00270 TCCR1A |= _BV(COM1C1);
00271
00272 TCCR1C = _BV(FOC1C);
00273
00274 return 0;
00275 }
00276
00277
00291 static int IrblastPut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00292 {
00293 int rc = 0;
00294 IRBLASTDCB *dcb = dev->dev_dcb;
00295 CONST u_short *cp;
00296 u_short ch;
00297
00298
00299 if (buffer == 0) {
00300 IrblastFlush(dev);
00301 }
00302
00303
00304
00305 cp = buffer;
00306
00307
00308 len >>= 1;
00309
00310 for (rc = 0; rc < len;) {
00311 if ((u_char) (dcb->if_wr_idx + 1) == dcb->if_tx_idx) {
00312 IrblastFlush(dev);
00313 }
00314 ch = pflg ? PRG_RDB(cp) : *cp;
00315 dcb->if_tx_buf[dcb->if_wr_idx] = ch;
00316 ++(dcb->if_wr_idx);
00317 ++cp;
00318 ++rc;
00319 }
00320
00321
00322 return (rc << 1);
00323 }
00324
00325
00335 static int IrblastWrite(NUTFILE * fp, CONST void *buffer, int len)
00336 {
00337 return IrblastPut(fp->nf_dev, buffer, len, 0);
00338 }
00339
00349 static int IrblastWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00350 {
00351 return IrblastPut(fp->nf_dev, (CONST char *) buffer, len, 1);
00352 }
00353
00363 static int IrblastIOCtl(NUTDEVICE * dev, int req, void *conf)
00364 {
00365 u_char *usp = (u_char *) conf;
00366
00367 switch (req) {
00368 case IRBLAST_SETFREQ:
00369 if (*usp == 0) {
00370
00371 TCCR2 &= ~(_BV(WGM21) | _BV(COM20));
00372 } else {
00373 OCR2 = *usp;
00374
00375
00376 TCNT2 = 0;
00377
00378
00379 TCCR2 |= _BV(WGM21) | _BV(COM20);
00380 }
00381 break;
00382
00383 case IRBLAST_GETFREQ:
00384 *usp = OCR2;
00385 break;
00386
00387 default:
00388 return -1;
00389 }
00390 return 0;
00391 }
00392
00403 static NUTFILE *IrblastOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00404 {
00405 file.nf_next = 0;
00406 file.nf_dev = dev;
00407 file.nf_fcb = 0;
00408 return &file;
00409 }
00410
00418 static int IrblastClose(NUTFILE * fp)
00419 {
00420 return 0;
00421 }
00422
00428 static void IrblastTmr1Init(void)
00429 {
00430
00431 TCCR1A &= ~(_BV(COM1C1) | _BV(COM1C0) | _BV(WGM11) | _BV(WGM10));
00432 TCCR1A |= _BV(COM1C1);
00433
00434 TCCR1B &= ~(_BV(WGM13) | _BV(WGM12) | _BV(CS12) | _BV(CS11) | _BV(CS10));
00435 TCCR1B |= _BV(WGM12);
00436
00437 TCCR1C = _BV(FOC1C);
00438
00439
00440 ETIMSK &= ~_BV(OCIE1C);
00441 }
00442
00448 static void IrblastTmr2Init(void)
00449 {
00450
00451 TCCR2 = _BV(CS20);
00452 }
00453
00454
00462 static int IrblastInit(NUTDEVICE * dev)
00463 {
00464 IRBLASTDCB *dcb = dev->dev_dcb;
00465
00466
00467 memset(dcb, 0, sizeof(IRBLASTDCB));
00468
00469
00470 if (NutRegisterIrqHandler(&sig_OUTPUT_COMPARE1C, IrblastOutComp1CInt, dev))
00471 return -1;
00472
00473
00474 IrblastTmr2Init();
00475
00476
00477 IrblastTmr1Init();
00478
00479
00480 sbi(DDRB, PORTB7);
00481
00482 return 0;
00483 }
00484
00485
00486
00487 NUTDEVICE devIrblast0 = {
00488 0,
00489 {'i', 'r', 'b', 'l', 'a', 's', 't', '0', 0}
00490 ,
00491 IFTYP_STREAM,
00492 0,
00493 0,
00494 0,
00495 &dcb_pwm0,
00496 IrblastInit,
00497 IrblastIOCtl,
00498 0,
00499 IrblastWrite,
00500 IrblastWrite_P,
00501 IrblastOpen,
00502 IrblastClose,
00503 0
00504 };