Rev 1972 | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 547 | andfri | 1 | /** |
| 610 | arune | 2 | * IR receiver and transmitter driver. |
| 547 | andfri | 3 | * |
| 4 | * @date 2006-12-10 |
||
| 5 | * |
||
| 610 | arune | 6 | * @author Anders Runeson, Andreas Fritiofson |
| 547 | andfri | 7 | * |
| 8 | */ |
||
| 9 | |||
| 10 | /*----------------------------------------------------------------------------- |
||
| 11 | * Includes |
||
| 12 | *---------------------------------------------------------------------------*/ |
||
| 13 | #include <config.h> |
||
| 14 | #include <drivers/ir/transceiver/irtransceiver.h> |
||
| 608 | arune | 15 | #include <drivers/ir/protocols.h> |
| 547 | andfri | 16 | #include <avr/io.h> |
| 17 | #include <avr/interrupt.h> |
||
| 18 | |||
| 19 | /*----------------------------------------------------------------------------- |
||
| 20 | * Globals |
||
| 21 | *---------------------------------------------------------------------------*/ |
||
| 1435 | arune | 22 | #if IR_RX_ENABLE==1 |
| 23 | uint16_t *rxbuf; |
||
| 24 | uint8_t rxlen; |
||
| 25 | #endif |
||
| 26 | #if IR_TX_ENABLE==1 |
||
| 27 | uint16_t *txbuf; |
||
| 28 | uint8_t txlen; |
||
| 29 | #endif |
||
| 608 | arune | 30 | |
| 1435 | arune | 31 | #if IR_TX_ENABLE==1 |
| 608 | arune | 32 | static uint8_t bufIndex; //selects the pulse width in buffer to send |
| 1435 | arune | 33 | #endif |
| 547 | andfri | 34 | volatile uint8_t data_received; |
| 552 | andfri | 35 | volatile uint8_t data_transmitted; |
| 547 | andfri | 36 | uint8_t detect_edge; |
| 37 | uint8_t store; |
||
| 38 | |||
| 39 | /*----------------------------------------------------------------------------- |
||
| 40 | * Prerequisites |
||
| 41 | *---------------------------------------------------------------------------*/ |
||
| 1435 | arune | 42 | #ifndef IR_RX_ACTIVE_LOW |
| 43 | #define IR_RX_ACTIVE_LOW 1 |
||
| 44 | #endif |
||
| 45 | |||
| 1431 | arune | 46 | #ifndef IR_TX_ACTIVE_LOW |
| 47 | #define IR_TX_ACTIVE_LOW 0 |
||
| 48 | #endif |
||
| 601 | arune | 49 | |
| 1435 | arune | 50 | #ifndef IR_TX_ENABLE |
| 51 | #define IR_TX_ENABLE 0 |
||
| 52 | #endif |
||
| 53 | |||
| 54 | #ifndef IR_RX_ENABLE |
||
| 55 | #define IR_RX_ENABLE 0 |
||
| 56 | #endif |
||
| 57 | |||
| 1480 | arune | 58 | #ifndef IR_TX_HACK |
| 59 | #define IR_TX_HACK 0 |
||
| 60 | #endif |
||
| 1435 | arune | 61 | |
| 1480 | arune | 62 | |
| 547 | andfri | 63 | #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) |
| 64 | #define TIMSK1 TIMSK |
||
| 65 | #define TIFR1 TIFR |
||
| 66 | #define ICIE1 TICIE1 |
||
| 67 | #endif |
||
| 68 | |||
| 552 | andfri | 69 | #define IR_COMPARE_VECTOR TIMER1_COMPB_vect |
| 70 | #define IR_TIMEOUT_VECTOR TIMER1_COMPA_vect |
||
| 71 | #define IR_CAPTURE_VECTOR TIMER1_CAPT_vect |
||
| 72 | #define IR_TIMEOUT_REG OCR1A |
||
| 73 | #define IR_COMPARE_REG OCR1B |
||
| 74 | #define IR_CAPTURE_REG ICR1 |
||
| 75 | #define IR_COUNT_REG TCNT1 |
||
| 608 | arune | 76 | #define IR_MODULATION_REG OCR0A |
| 552 | andfri | 77 | #define IR_TIMER_INIT() TCCR1A = 0; \ |
| 78 | TCCR1B = (1<<ICNC1)|(2<<CS10); |
||
| 79 | #define IR_MASK_COMPARE() TIMSK1 &= ~(1<<OCIE1B); |
||
| 80 | #define IR_UNMASK_COMPARE() TIFR1 = (1<<OCF1B); TIMSK1 |= (1<<OCIE1B); |
||
| 81 | #define IR_MASK_TIMEOUT() TIMSK1 &= ~(1<<OCIE1A); |
||
| 82 | #define IR_UNMASK_TIMEOUT() TIFR1 = (1<<OCF1A); TIMSK1 |= (1<<OCIE1A); |
||
| 83 | #define IR_MASK_CAPTURE() TIMSK1 &= ~(1<<ICIE1); |
||
| 84 | #define IR_UNMASK_CAPTURE() TIFR1 = (1<<ICF1); TIMSK1 |= (1<<ICIE1); |
||
| 85 | #define IR_CAPTURE_FALLING() TCCR1B &= ~(1<<ICES1); \ |
||
| 86 | TIFR1 = (1<<ICF1); |
||
| 87 | #define IR_CAPTURE_RISING() TCCR1B |= (1<<ICES1); \ |
||
| 88 | TIFR1 = (1<<ICF1); |
||
| 547 | andfri | 89 | |
| 1480 | arune | 90 | #if IR_TX_HACK==0 |
| 601 | arune | 91 | #define IR_OUTP_HIGH() TCCR0A |= (1<<COM0A0); |
| 92 | #define IR_OUTP_LOW() TCCR0A &= ~(1<<COM0A0); |
||
| 1480 | arune | 93 | #endif |
| 547 | andfri | 94 | |
| 1480 | arune | 95 | #if IR_TX_HACK==1 |
| 96 | #define IR_T_PORT_HACK PORTD |
||
| 97 | #define IR_T_PIN_HACK PIND |
||
| 98 | #define IR_T_DDR_HACK DDRD |
||
| 99 | #define IR_T_BIT_HACK PD5 |
||
| 601 | arune | 100 | |
| 1480 | arune | 101 | #define IR_OUTP_HIGH() IR_T_PORT_HACK &= ~(1<<IR_T_BIT_HACK); |
| 102 | #define IR_OUTP_LOW() IR_T_PORT_HACK |= (1<<IR_T_BIT_HACK); |
||
| 103 | #endif |
||
| 104 | |||
| 105 | |||
| 106 | |||
| 547 | andfri | 107 | /*----------------------------------------------------------------------------- |
| 108 | * Interrupt Handlers |
||
| 109 | *---------------------------------------------------------------------------*/ |
||
| 110 | |||
| 1435 | arune | 111 | #if IR_TX_ENABLE==1 |
| 552 | andfri | 112 | ISR(IR_COMPARE_VECTOR) |
| 547 | andfri | 113 | { |
| 608 | arune | 114 | if ((bufIndex&1) == 1) { /* if odd, ir-pause */ |
| 601 | arune | 115 | IR_OUTP_LOW(); |
| 116 | } else { |
||
| 117 | IR_OUTP_HIGH(); |
||
| 118 | } |
||
| 119 | |||
| 727 | noddan | 120 | //The following three lines is just to allow a start signal to be zero. |
| 121 | /* bufIndex++; |
||
| 122 | while (txbuf[bufIndex] == 0){ |
||
| 123 | bufIndex++; |
||
| 124 | }*/ |
||
| 125 | |||
| 608 | arune | 126 | if (bufIndex < txlen) |
| 727 | noddan | 127 | { |
| 608 | arune | 128 | IR_COMPARE_REG += txbuf[bufIndex++]; |
| 129 | //IR_COMPARE_REG += *(txbuf + bufIndex++); |
||
| 552 | andfri | 130 | } |
| 131 | else |
||
| 132 | { |
||
| 133 | IR_MASK_COMPARE(); |
||
| 134 | data_transmitted = 1; |
||
| 135 | } |
||
| 547 | andfri | 136 | } |
| 1435 | arune | 137 | #endif |
| 547 | andfri | 138 | |
| 1435 | arune | 139 | #if IR_RX_ENABLE==1 |
| 552 | andfri | 140 | ISR(IR_TIMEOUT_VECTOR) |
| 547 | andfri | 141 | { |
| 608 | arune | 142 | if (rxlen) |
| 547 | andfri | 143 | { |
| 144 | /* Disable interrupts until the application has taken action on the |
||
| 145 | * current data and reenabled reception. */ |
||
| 552 | andfri | 146 | IR_MASK_CAPTURE(); |
| 147 | IR_MASK_TIMEOUT(); |
||
| 547 | andfri | 148 | /* Notify the application that a pulse train has been received. */ |
| 149 | data_received = 1; |
||
| 150 | } |
||
| 151 | store = 0; |
||
| 152 | } |
||
| 1435 | arune | 153 | #endif |
| 547 | andfri | 154 | |
| 1435 | arune | 155 | #if IR_RX_ENABLE==1 |
| 552 | andfri | 156 | ISR(IR_CAPTURE_VECTOR) |
| 547 | andfri | 157 | { |
| 552 | andfri | 158 | static uint16_t prev_time; |
| 159 | uint16_t pulsewidth; |
||
| 160 | |||
| 161 | /* Read the measured transition time from the capture register. */ |
||
| 162 | uint16_t time = IR_CAPTURE_REG; |
||
| 547 | andfri | 163 | |
| 164 | /* Toggle the edge detection. */ |
||
| 165 | if (detect_edge == 0) |
||
| 166 | { |
||
| 552 | andfri | 167 | IR_CAPTURE_RISING(); |
| 547 | andfri | 168 | detect_edge = 1; |
| 169 | } |
||
| 170 | else |
||
| 171 | { |
||
| 552 | andfri | 172 | IR_CAPTURE_FALLING(); |
| 547 | andfri | 173 | detect_edge = 0; |
| 174 | } |
||
| 175 | |||
| 552 | andfri | 176 | /* Subtract the current measurement from the previous to get the pulse |
| 177 | * width. */ |
||
| 178 | pulsewidth = time - prev_time; |
||
| 179 | prev_time = time; |
||
| 180 | |||
| 181 | /* Set the timeout. */ |
||
| 182 | IR_TIMEOUT_REG = time + IR_MAX_PULSE_WIDTH; |
||
| 183 | |||
| 547 | andfri | 184 | if (store) |
| 185 | { |
||
| 186 | /* Store the measurement. */ |
||
| 608 | arune | 187 | rxbuf[rxlen++] = pulsewidth; |
| 188 | //*(rxbuf+rxlen++) = pulsewidth; |
||
| 547 | andfri | 189 | /* Disable future measurements if we've filled the buffer. */ |
| 190 | //TODO: Report overflow to application |
||
| 608 | arune | 191 | if (rxlen == MAX_NR_TIMES) |
| 547 | andfri | 192 | { |
| 552 | andfri | 193 | IR_MASK_CAPTURE(); |
| 547 | andfri | 194 | } |
| 195 | } |
||
| 196 | else |
||
| 197 | { |
||
| 198 | /* The first edge of the pulse train has been detected. Enable the |
||
| 199 | * storage of the following pulsewidths. */ |
||
| 200 | store = 1; |
||
| 201 | /* Enable timeout interrupt for detection of the end of the pulse |
||
| 202 | * train. */ |
||
| 552 | andfri | 203 | IR_UNMASK_TIMEOUT(); |
| 547 | andfri | 204 | } |
| 205 | } |
||
| 1435 | arune | 206 | #endif |
| 547 | andfri | 207 | |
| 208 | |||
| 209 | /*----------------------------------------------------------------------------- |
||
| 210 | * Public Functions |
||
| 211 | *---------------------------------------------------------------------------*/ |
||
| 212 | |||
| 213 | void IrTransceiver_Init(void) |
||
| 214 | { |
||
| 1435 | arune | 215 | IR_TIMER_INIT(); |
| 216 | #if IR_RX_ENABLE==1 |
||
| 601 | arune | 217 | /* Set up receiver */ |
| 547 | andfri | 218 | IR_TIMEOUT_REG = IR_MAX_PULSE_WIDTH; |
| 601 | arune | 219 | IR_R_DDR &= ~(1<<IR_R_BIT); |
| 220 | //DDRC |= (1<<PC5); |
||
| 1435 | arune | 221 | #endif |
| 601 | arune | 222 | |
| 1435 | arune | 223 | #if IR_TX_ENABLE==1 |
| 601 | arune | 224 | /* Set up transmitter */ |
| 225 | IR_T_DDR |= (1<<IR_T_BIT); |
||
| 1468 | arune | 226 | #if defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) |
| 601 | arune | 227 | TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(1<<WGM01)|(0<<WGM00); |
| 228 | TCCR0B = (0<<WGM02)|(1<<CS00)|(0<<CS01)|(0<<CS02); |
||
| 229 | #endif |
||
| 1431 | arune | 230 | |
| 1480 | arune | 231 | #if IR_TX_HACK==0 |
| 1431 | arune | 232 | #if IR_TX_ACTIVE_LOW==1 |
| 233 | /* when pwm is disconnected from port (during low) the port should output 5V */ |
||
| 234 | IR_T_PORT |= (1<<IR_T_BIT); |
||
| 235 | #else |
||
| 236 | /* when pwm is disconnected from port (during low) the port should output 0V */ |
||
| 237 | IR_T_PORT &= ~(1<<IR_T_BIT); |
||
| 238 | #endif |
||
| 1480 | arune | 239 | #endif |
| 1435 | arune | 240 | |
| 1480 | arune | 241 | #if IR_TX_HACK==1 |
| 242 | /* Set up transmitter */ |
||
| 243 | IR_T_DDR_HACK |= (1<<IR_T_BIT_HACK); |
||
| 244 | |||
| 245 | /* when pwm is disconnected from port (during low) the port should output 5V */ |
||
| 246 | IR_T_PORT_HACK |= (1<<IR_T_BIT_HACK); |
||
| 247 | |||
| 248 | IR_MODULATION_REG = (((F_CPU/2000)/38) -1); |
||
| 249 | |||
| 250 | /* start pwm generator */ |
||
| 251 | TCCR0A |= (1<<COM0A0); |
||
| 1435 | arune | 252 | #endif |
| 1480 | arune | 253 | |
| 254 | #endif |
||
| 547 | andfri | 255 | } |
| 256 | |||
| 610 | arune | 257 | void IrTransceiver_Receive_Start(uint16_t *buffer) |
| 547 | andfri | 258 | { |
| 1435 | arune | 259 | #if IR_RX_ENABLE==1 |
| 608 | arune | 260 | /* Setup buffer and arm the edge detection. */ |
| 261 | rxbuf = buffer; |
||
| 262 | rxlen = 0; |
||
| 547 | andfri | 263 | data_received = 0; |
| 264 | store = 0; |
||
| 265 | #if (IR_RX_ACTIVE_LOW == 1) |
||
| 552 | andfri | 266 | IR_CAPTURE_FALLING(); |
| 547 | andfri | 267 | detect_edge = 0; |
| 268 | #else |
||
| 552 | andfri | 269 | IR_CAPTURE_RISING(); |
| 547 | andfri | 270 | detect_edge = 1; |
| 271 | #endif |
||
| 552 | andfri | 272 | IR_UNMASK_CAPTURE(); |
| 1435 | arune | 273 | #endif |
| 547 | andfri | 274 | } |
| 275 | |||
| 613 | arune | 276 | uint8_t IrTransceiver_Receive_Poll(uint8_t *len) |
| 547 | andfri | 277 | { |
| 1435 | arune | 278 | #if IR_RX_ENABLE==1 |
| 613 | arune | 279 | *len = rxlen; |
| 547 | andfri | 280 | if (data_received) |
| 281 | { |
||
| 613 | arune | 282 | return IR_OK; |
| 547 | andfri | 283 | } |
| 613 | arune | 284 | else if (rxlen > 0) |
| 547 | andfri | 285 | { |
| 613 | arune | 286 | return IR_NOT_FINISHED; |
| 287 | } else { |
||
| 288 | return IR_NO_DATA; |
||
| 547 | andfri | 289 | } |
| 1435 | arune | 290 | #else |
| 291 | return 0; |
||
| 292 | #endif |
||
| 547 | andfri | 293 | } |
| 294 | |||
| 601 | arune | 295 | uint8_t IrTransceiver_Transmit_Poll(void) { |
| 1435 | arune | 296 | #if IR_TX_ENABLE==1 |
| 601 | arune | 297 | if (data_transmitted == 0) { |
| 298 | return IR_NOT_FINISHED; |
||
| 299 | } else { |
||
| 300 | return IR_OK; |
||
| 301 | } |
||
| 1435 | arune | 302 | #else |
| 303 | return 0; |
||
| 304 | #endif |
||
| 601 | arune | 305 | } |
| 306 | |||
| 608 | arune | 307 | uint8_t IrTransceiver_Transmit(uint16_t *buffer, uint8_t length, uint8_t modfreq) |
| 601 | arune | 308 | { |
| 1435 | arune | 309 | #if IR_TX_ENABLE==1 |
| 601 | arune | 310 | data_transmitted = 0; |
| 311 | |||
| 608 | arune | 312 | if (length == 0) return IR_NO_DATA; |
| 601 | arune | 313 | |
| 608 | arune | 314 | txbuf = buffer; |
| 315 | txlen = length; |
||
| 316 | bufIndex = 1; |
||
| 547 | andfri | 317 | |
| 1972 | arune | 318 | IR_MODULATION_REG = (((F_CPU/2000)/modfreq) -1); |
| 547 | andfri | 319 | |
| 608 | arune | 320 | IR_COMPARE_REG = IR_COUNT_REG + txbuf[0]; |
| 547 | andfri | 321 | |
| 608 | arune | 322 | IR_OUTP_HIGH(); |
| 547 | andfri | 323 | |
| 608 | arune | 324 | IR_UNMASK_COMPARE(); |
| 547 | andfri | 325 | |
| 608 | arune | 326 | //while (!data_transmitted); |
| 547 | andfri | 327 | |
| 328 | return IR_OK; |
||
| 1435 | arune | 329 | #else |
| 330 | return 0; |
||
| 331 | #endif |
||
| 547 | andfri | 332 | } |