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 };