Firmware SDK
twr_ir_rx.c
1 
2 #include <stm32l0xx.h>
3 #include <twr_common.h>
4 #include <twr_gpio.h>
5 #include <twr_exti.h>
6 #include <twr_scheduler.h>
7 #include <twr_system.h>
8 #include <twr_ir_rx.h>
9 #include <twr_timer.h>
10 
11 //#define _TWR_IR_RX_DEBUG
12 
13 // IR receiver has to be connected on
14 // TWR_GPIO_P10
15 // No external pull-up required, internal pull-up is activated
16 
17 static struct
18 {
19  TIM_HandleTypeDef ir_timer;
20  uint8_t counter;
21  uint32_t ir_rx_temp;
22  uint32_t ir_rx_value;
23 
24  twr_scheduler_task_id_t task_id_notify;
25 
26  void (*event_handler)(twr_ir_rx_event_t, void *);
27  void *event_param;
28 
29  #ifdef _TWR_IR_RX_DEBUG
30  uint16_t lengths[40];
31  #endif
32 } _twr_ir_rx;
33 
34 static void TIM6_handler(void *param);
35 
36 void twr_ir_rx_get_code(uint32_t *nec_code)
37 {
38  *nec_code = _twr_ir_rx.ir_rx_value;
39 }
40 
41 
42 static void _twr_ir_rx_task_notify(void *param)
43 {
44  (void) param;
45 
46  if (_twr_ir_rx.event_handler != NULL)
47  {
48  _twr_ir_rx.event_handler(TWR_IR_RX_NEC_FORMAT, _twr_ir_rx.event_param);
49  }
50 }
51 
52 static void _twr_ir_rx_exti_int(twr_exti_line_t line, void *param)
53 {
54  (void) param;
55  (void) line;
56 
57  #ifdef _TWR_IR_RX_DEBUG
59  #endif
60 
61  if(_twr_ir_rx.counter == 0)
62  {
63  // Start pulse, start timer
64  __HAL_TIM_DISABLE(&_twr_ir_rx.ir_timer);
65  __HAL_TIM_DISABLE_IT(&_twr_ir_rx.ir_timer, TIM_IT_UPDATE);
66  __HAL_TIM_CLEAR_IT(&_twr_ir_rx.ir_timer, TIM_IT_UPDATE);
67 
68  HAL_TIM_Base_Start_IT(&_twr_ir_rx.ir_timer);
69  _twr_ir_rx.counter++;
70  return;
71  }
72 
73  // Get value and clear the timer
74  uint16_t act_len = __HAL_TIM_GET_COUNTER(&_twr_ir_rx.ir_timer);
75  __HAL_TIM_SET_COUNTER(&_twr_ir_rx.ir_timer, 0);
76 
77  // Array for debugging
78  #ifdef _TWR_IR_RX_DEBUG
79  _twr_ir_rx.lengths[_twr_ir_rx.counter] = act_len;
80  #endif
81 
82  // Check start pulse length
83  if(_twr_ir_rx.counter == 1)
84  {
85  if(act_len < 8000 || act_len > 14000)
86  {
87  // Ignore this packet
88  volatile int a = 5;
89  a++;
90  return;
91  }
92  }
93 
94  if(_twr_ir_rx.counter == 2)
95  {
96  _twr_ir_rx.ir_rx_temp = 0;
97  }
98 
99  // ignore first two items (first zero value and start pulse)
100  if(act_len > 1500 && _twr_ir_rx.counter >= 2)
101  {
102  _twr_ir_rx.ir_rx_temp |= (1 << (_twr_ir_rx.counter-2));
103  }
104 
105  // Received packet
106  if(_twr_ir_rx.counter == 33)
107  {
108  #ifdef _TWR_IR_RX_DEBUG
109  // Debug toggle
113  #endif
114 
115  _twr_ir_rx.counter = 0;
116  _twr_ir_rx.ir_rx_value = _twr_ir_rx.ir_rx_temp;
117 
118  // The ir_rx_value should have inverted one addr and one command byte, but
119  // the test of my IR remotes shows, that only the second CMD byte is inversion of the fist one
120 
121  __HAL_TIM_DISABLE(&_twr_ir_rx.ir_timer);
122  __HAL_TIM_DISABLE_IT(&_twr_ir_rx.ir_timer, TIM_IT_UPDATE);
123  __HAL_TIM_CLEAR_IT(&_twr_ir_rx.ir_timer, TIM_IT_UPDATE);
124 
125  twr_scheduler_plan_now(_twr_ir_rx.task_id_notify);
126 
127  return;
128  }
129 
130  _twr_ir_rx.counter++;
131 }
132 
133 void twr_ir_rx_set_event_handler(void (*event_handler)(twr_ir_rx_event_t, void *), void *event_param)
134 {
135  _twr_ir_rx.event_handler = event_handler;
136  _twr_ir_rx.event_param = event_param;
137 }
138 
139 void twr_ir_rx_init()
140 {
141  // TODO: Needs fix to allow low power
142  twr_system_pll_enable();
143 
144  // IR input
148  // External interrupt
149  twr_exti_register(TWR_EXTI_LINE_P10, TWR_EXTI_EDGE_FALLING, _twr_ir_rx_exti_int, NULL);
150 
151  #ifdef _TWR_IR_RX_DEBUG
152  // Debug output
155  #endif
156 
157  // Used TIM6 so we don't have collision of IRQ handlers functions
158  __TIM6_CLK_ENABLE();
159  _twr_ir_rx.ir_timer.Instance = TIM6;
160  // Running @ 32MHz, set timer to 1us resolution
161  _twr_ir_rx.ir_timer.Init.Prescaler = SystemCoreClock / 1000000;
162  _twr_ir_rx.ir_timer.Init.CounterMode = TIM_COUNTERMODE_UP;
163  // Period is also the timeout in case the IR code is not complete
164  _twr_ir_rx.ir_timer.Init.Period = 16000;
165  _twr_ir_rx.ir_timer.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
166  HAL_TIM_Base_Init(&_twr_ir_rx.ir_timer);
167  HAL_NVIC_EnableIRQ(TIM6_IRQn);
168 
169  twr_timer_set_irq_handler(TIM6, TIM6_handler, NULL);
170 
171 
172  _twr_ir_rx.task_id_notify = twr_scheduler_register(_twr_ir_rx_task_notify, NULL, TWR_TICK_INFINITY);
173 
174 }
175 
176 static void TIM6_handler(void *param)
177 {
178  (void) param;
179 
180  #ifdef _TWR_IR_RX_DEBUG
185  #endif
186 
187  if(__HAL_TIM_GET_FLAG(&_twr_ir_rx.ir_timer, TIM_FLAG_UPDATE) != RESET)
188  {
189  if(__HAL_TIM_GET_IT_SOURCE(&_twr_ir_rx.ir_timer, TIM_IT_UPDATE) !=RESET)
190  {
191  // Stop timer
192  __HAL_TIM_CLEAR_IT(&_twr_ir_rx.ir_timer, TIM_IT_UPDATE);
193  __HAL_TIM_DISABLE(&_twr_ir_rx.ir_timer);
194  __HAL_TIM_DISABLE_IT(&_twr_ir_rx.ir_timer, TIM_IT_UPDATE);
195 
196  _twr_ir_rx.counter = 0;
197  }
198  }
199 }
void twr_exti_register(twr_exti_line_t line, twr_exti_edge_t edge, void(*callback)(twr_exti_line_t, void *), void *param)
Enable EXTI line interrupt and register callback function.
Definition: twr_exti.c:17
twr_exti_line_t
EXTI lines.
Definition: twr_exti.h:22
@ TWR_EXTI_LINE_P10
EXTI line P10.
Definition: twr_exti.h:165
@ TWR_EXTI_EDGE_FALLING
EXTI line is configured to falling edge sensitivity.
Definition: twr_exti.h:201
void twr_gpio_set_pull(twr_gpio_channel_t channel, twr_gpio_pull_t pull)
Set pull-up/pull-down configuration for GPIO channel.
Definition: twr_gpio.c:340
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
void twr_gpio_toggle_output(twr_gpio_channel_t channel)
Toggle output state for GPIO channel.
Definition: twr_gpio.c:483
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: twr_gpio.c:367
@ TWR_GPIO_MODE_INPUT
GPIO channel operates as input.
Definition: twr_gpio.h:105
@ TWR_GPIO_MODE_OUTPUT
GPIO channel operates as output.
Definition: twr_gpio.h:108
@ TWR_GPIO_P11
GPIO channel P11, TXD2.
Definition: twr_gpio.h:48
@ TWR_GPIO_P10
GPIO channel P10, RXD2.
Definition: twr_gpio.h:45
@ TWR_GPIO_PULL_UP
GPIO channel has pull-up.
Definition: twr_gpio.h:93
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: twr_scheduler.h:22
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
bool twr_timer_set_irq_handler(TIM_TypeDef *tim, void(*irq_handler)(void *), void *irq_param)
Register timer IRQ handler.
Definition: twr_timer.c:86