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