From e813e6bf462b8cb6a2f910745f0890bed71e9407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Wed, 12 Oct 2022 17:37:00 +0200 Subject: [PATCH] main: add NEC code transmission --- main.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 17 deletions(-) diff --git a/main.c b/main.c index cb01af4..783edd8 100644 --- a/main.c +++ b/main.c @@ -174,6 +174,82 @@ static void timer_ir_in(void) IRM_ON_PORT->ODR.reg |= IRM_ON_PIN; // switch IR demodulator on } +#define TIM1_PERIOD 421U // 16E6/(0+1)/38000 + +// configure timer to transmit IR burst at 38 kHz +static void timer_ir_out(void) +{ + IRM_ON_PORT->ODR.reg &= ~IRM_ON_PIN; // switch IR demodulator off + + TIM1->CR1.reg = 0; // disable counter before reconfiguring it + TIM1->CCER1.reg = 0; // reset register + TIM1->CCER2.reg = 0; // reset register + TIM1->IER.reg = 0; // reset interrupts + TIM1->PSCRH.reg = 0; // set prescaler to get most precise 38 kHz + TIM1->PSCRL.reg = 0; // 16E6/(0+1)/65536 = down to 244 Hz + TIM1->ARRH.reg = (TIM1_PERIOD >> 8); // set auto-reload register for 38 kHz period + TIM1->ARRL.reg = (TIM1_PERIOD & 0xff); // 16E6/(0+1)/38000 + TIM1->CCR4H.reg = (TIM1_PERIOD / 3) >> 8; // set duty cycle to 33% + TIM1->CCR4L.reg = (TIM1_PERIOD / 3 ) & 0xff; // set duty cycle to 33% + TIM1->CCMR4.output_fields.OC4M = 6; // set PWM1 mode + TIM1->CCMR4.output_fields.CC4S = 0; // use channel as output + TIM1->CCER2.fields.CC4E = 1; // enable channel output + TIM1->BKR.fields.MOE = 1; // enable outputs + TIM1->SR1.reg = 0; // clear all flags + TIM1->CNTRL.reg = 0; // reset counter + TIM1->CNTRH.reg = 0; // reset counter + TIM1->CR1.fields.OPM = 1; // send one pulse at a time + TIM1->EGR.fields.UG = 1; // transfer all registers + // don't enable timer yet +} + +// transmit IR pulses +static void nec_pulse(uint16_t pulses, bool mark) +{ + if (mark) { + TIM1->CCR4H.reg = (TIM1_PERIOD / 3) >> 8; // set duty cycle to 33% + TIM1->CCR4L.reg = (TIM1_PERIOD / 3 ) & 0xff; // set duty cycle to 33% + } else { + TIM1->CCR4H.reg = 0; // set duty cycle to 0% + TIM1->CCR4L.reg = 0; // set duty cycle to 0% + } + while (pulses--) { + TIM1->CR1.fields.CEN = 1; // enable counter to start PWM for 1 pulse + while (TIM1->CR1.fields.CEN); // wait until pulse completes + } + // ensure we are off at the end + TIM1->CCR4H.reg = 0; // set duty cycle to 0% + TIM1->CCR4L.reg = 0; // set duty cycle to 0% +} + +// transmit 4 byte NEC code over IR (LSb first) +static void nec_transmit(uint32_t code) +{ + if (NULL == code) { + return; + } + + timer_ir_out(); // configure to transmit pulses + sim(); // disable interrupts to keep timings tight + // all time are hand tuned + nec_pulse(333, true); // send AGC burst, 9 ms + nec_pulse(166, false); // AGC space, 4.5 ms + // transmit bits + for (uint8_t i = 0; i < 32; i++) { + nec_pulse(21, true); // bit burst, 560 us + if (code & 0x1) { + nec_pulse(61, false); // bit space, 2.25 ms - 560 us + } else { + nec_pulse(21, false); // bit space, 1.12 ms - 560 us + } + code >>= 1; // go to next bit + } + nec_pulse(22, true); // end pulse, 560 us + rim(); // re-enable interrupts + + timer_ir_in(); // go back to IR capture +} + void main(void) { sim(); // disable interrupts (while we reconfigure them) @@ -265,23 +341,6 @@ void main(void) TIM4->CR1.fields.URS = 1; // only update on overflow TIM4->CR1.fields.CEN = 1; // enable counter -/* - // configure timer to modulate IR LEDs at 38 kHz - TIM1->PSCRH.reg = 0; // set prescaler to get most precise 38 kHz - TIM1->PSCRL.reg = 0; // 16E6/(0+1)/65536 = down to 244 Hz - #define TIM1_PERIOD 421U // 16E6/(0+1)/38000 - TIM1->ARRH.reg = (TIM1_PERIOD >> 8); // set auto-reload register for 38 kHz period - TIM1->ARRL.reg = (TIM1_PERIOD & 0xff); // 16E6/(0+1)/38000 - TIM1->CCR4H.reg = (TIM1_PERIOD / 3) >> 8; // set duty cycle to 33% - TIM1->CCR4L.reg = (TIM1_PERIOD / 3 ) & 0xff; // set duty cycle to 33% - TIM1->CCMR4.output_fields.OC4M = 6; // set PWM1 mode - TIM1->CCMR4.output_fields.CC4S = 0; // use channel as output - TIM1->CCER2.fields.CC4E = 1; // enable channel output - TIM1->BKR.fields.MOE = 1; // enable outputs - TIM1->EGR.fields.UG = 1; // transfer all registers - TIM1->CR1.fields.CEN = 1; // enable counter to start PWM -*/ - // configure timer to receive IR message timer_ir_in();