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 #include <compiler.h>
00051 #include <string.h>
00052 #include <dev/irqreg.h>
00053 #include <sys/atom.h>
00054 #include <sys/event.h>
00055 #include <sys/thread.h>
00056 #include <sys/device.h>
00057 #include <arch/timer.h>
00058 #include <dev/irblast.h>
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 typedef struct _IRBLASTDCB IRBLASTDCB;
00092 struct _IRBLASTDCB {
00093
00094
00095
00096 HANDLE dcb_tx_rdy;
00097
00098
00099 volatile uint8_t if_tx_idx;
00100
00101 uint8_t if_wr_idx;
00102
00103 volatile uint8_t if_tx_act;
00104
00105 uint16_t if_tx_buf[256];
00106 };
00107
00108 static IRBLASTDCB dcb_pwm0;
00109 static NUTFILE file;
00110
00111
00119 uint8_t IrblastFreq2Ocr(uint8_t freqKHz)
00120 {
00121 uint32_t div;
00122 uint8_t ocr = 0;
00123
00124 if ((freqKHz >= 30) && (freqKHz <= 50)) {
00125
00126 div = 2000UL * (uint32_t) freqKHz;
00127 ocr = (uint8_t) ((NutGetCpuClock() / div) & 0x000000ff) - 1;
00128 }
00129 return ocr;
00130 }
00131
00144 int IrblastPeriod2Ocr(uint8_t freqKHz, int entries, uint16_t * pCode)
00145 {
00146 uint32_t div, sClk, freq;
00147 int i = -1;
00148
00149 if ((freqKHz < 30) && (freqKHz > 50)) {
00150 freqKHz = 100;
00151 }
00152
00153
00154 sClk = NutGetCpuClock() / 10UL;
00155 freq = 800UL * (uint32_t) (freqKHz);
00156
00157 for (i = 0; i < entries; ++i) {
00158 if ((pCode[i] == 0) || (pCode[i] > 1000)) {
00159 return -1;
00160 }
00161 div = sClk * (uint32_t) pCode[i];
00162 div = div / freq;
00163 pCode[i] = (unsigned int) (div & 0x0000ffff) - 1;
00164 }
00165 return i;
00166 }
00167
00168
00177 static void IrblastOutComp1CInt(void *arg)
00178 {
00179 NUTDEVICE *dev = (NUTDEVICE *) arg;
00180 IRBLASTDCB *dcb = dev->dev_dcb;
00181
00182 if (dcb->if_tx_idx != dcb->if_wr_idx) {
00183
00184 OCR1A = dcb->if_tx_buf[dcb->if_tx_idx];
00185 OCR1C = dcb->if_tx_buf[dcb->if_tx_idx];
00186 ++(dcb->if_tx_idx);
00187 } else {
00188 dcb->if_tx_act = 0;
00189
00190
00191 TIMSK &= ~_BV(OCIE1C);
00192
00193 TCCR1B &= ~_BV(CS11);
00194
00195 TCCR1A &= ~_BV(COM1C0);
00196 TCCR1A |= _BV(COM1C1);
00197
00198 TCCR1C = _BV(FOC1C);
00199
00200 NutEventPostFromIrq(&dcb->dcb_tx_rdy);
00201 }
00202 }
00203
00204
00219 static int IrblastOutput(NUTDEVICE * dev)
00220 {
00221 IRBLASTDCB *dcb = dev->dev_dcb;
00222
00223 if ((dcb->if_tx_act == 0) && (dcb->if_tx_idx != dcb->if_wr_idx)) {
00224 dcb->if_tx_act = 1;
00225
00226 TCCR1A &= ~_BV(COM1C1);
00227 TCCR1A |= _BV(COM1C0);
00228
00229 TCCR1C = _BV(FOC1C);
00230
00231
00232 TCNT1 = 0;
00233
00234
00235 OCR1A = dcb->if_tx_buf[dcb->if_tx_idx];
00236 OCR1C = dcb->if_tx_buf[dcb->if_tx_idx];
00237
00238 ++(dcb->if_tx_idx);
00239
00240
00241 ETIMSK |= _BV(OCIE1C);
00242
00243 TCCR1B |= _BV(CS11);
00244 }
00245 return 0;
00246 }
00247
00248
00259 static int IrblastFlush(NUTDEVICE * dev)
00260 {
00261 IRBLASTDCB *dcb = dev->dev_dcb;
00262
00263
00264 IrblastOutput(dev);
00265
00266
00267 while (dcb->if_tx_idx != dcb->if_wr_idx) {
00268 NutEventWaitNext(&dcb->dcb_tx_rdy, 100);
00269 }
00270
00271
00272 ETIMSK &= ~_BV(OCIE1C);
00273
00274 TCCR1B &= ~_BV(CS11);
00275
00276 TCCR1A &= ~_BV(COM1C0);
00277 TCCR1A |= _BV(COM1C1);
00278
00279 TCCR1C = _BV(FOC1C);
00280
00281 return 0;
00282 }
00283
00284
00298 static int IrblastPut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00299 {
00300 int rc = 0;
00301 IRBLASTDCB *dcb = dev->dev_dcb;
00302 CONST uint16_t *cp;
00303 uint16_t ch;
00304
00305
00306 if (buffer == 0) {
00307 IrblastFlush(dev);
00308 }
00309
00310
00311
00312 cp = buffer;
00313
00314
00315 len >>= 1;
00316
00317 for (rc = 0; rc < len;) {
00318 if ((uint8_t) (dcb->if_wr_idx + 1) == dcb->if_tx_idx) {
00319 IrblastFlush(dev);
00320 }
00321 ch = pflg ? PRG_RDB(cp) : *cp;
00322 dcb->if_tx_buf[dcb->if_wr_idx] = ch;
00323 ++(dcb->if_wr_idx);
00324 ++cp;
00325 ++rc;
00326 }
00327
00328
00329 return (rc << 1);
00330 }
00331
00332
00342 static int IrblastWrite(NUTFILE * fp, CONST void *buffer, int len)
00343 {
00344 return IrblastPut(fp->nf_dev, buffer, len, 0);
00345 }
00346
00356 static int IrblastWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00357 {
00358 return IrblastPut(fp->nf_dev, (CONST char *) buffer, len, 1);
00359 }
00360
00370 static int IrblastIOCtl(NUTDEVICE * dev, int req, void *conf)
00371 {
00372 uint8_t *usp = (uint8_t *) conf;
00373
00374 switch (req) {
00375 case IRBLAST_SETFREQ:
00376 if (*usp == 0) {
00377
00378 TCCR2 &= ~(_BV(WGM21) | _BV(COM20));
00379 } else {
00380 OCR2 = *usp;
00381
00382
00383 TCNT2 = 0;
00384
00385
00386 TCCR2 |= _BV(WGM21) | _BV(COM20);
00387 }
00388 break;
00389
00390 case IRBLAST_GETFREQ:
00391 *usp = OCR2;
00392 break;
00393
00394 default:
00395 return -1;
00396 }
00397 return 0;
00398 }
00399
00410 static NUTFILE *IrblastOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00411 {
00412 file.nf_next = 0;
00413 file.nf_dev = dev;
00414 file.nf_fcb = 0;
00415 return &file;
00416 }
00417
00425 static int IrblastClose(NUTFILE * fp)
00426 {
00427 return 0;
00428 }
00429
00435 static void IrblastTmr1Init(void)
00436 {
00437
00438 TCCR1A &= ~(_BV(COM1C1) | _BV(COM1C0) | _BV(WGM11) | _BV(WGM10));
00439 TCCR1A |= _BV(COM1C1);
00440
00441 TCCR1B &= ~(_BV(WGM13) | _BV(WGM12) | _BV(CS12) | _BV(CS11) | _BV(CS10));
00442 TCCR1B |= _BV(WGM12);
00443
00444 TCCR1C = _BV(FOC1C);
00445
00446
00447 ETIMSK &= ~_BV(OCIE1C);
00448 }
00449
00455 static void IrblastTmr2Init(void)
00456 {
00457
00458 TCCR2 = _BV(CS20);
00459 }
00460
00461
00469 static int IrblastInit(NUTDEVICE * dev)
00470 {
00471 IRBLASTDCB *dcb = dev->dev_dcb;
00472
00473
00474 memset(dcb, 0, sizeof(IRBLASTDCB));
00475
00476
00477 if (NutRegisterIrqHandler(&sig_OUTPUT_COMPARE1C, IrblastOutComp1CInt, dev))
00478 return -1;
00479
00480
00481 IrblastTmr2Init();
00482
00483
00484 IrblastTmr1Init();
00485
00486
00487 sbi(DDRB, PORTB7);
00488
00489 return 0;
00490 }
00491
00492
00493
00494 NUTDEVICE devIrblast0 = {
00495 0,
00496 {'i', 'r', 'b', 'l', 'a', 's', 't', '0', 0}
00497 ,
00498 IFTYP_STREAM,
00499 0,
00500 0,
00501 0,
00502 &dcb_pwm0,
00503 IrblastInit,
00504 IrblastIOCtl,
00505 0,
00506 IrblastWrite,
00507 IrblastWrite_P,
00508 IrblastOpen,
00509 IrblastClose,
00510 0
00511 };