1 /*
2  * Copyright (c) 2020-2021, Bluetrum Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2021-04-12     greedyhao         first version
9  */
10 
11 #include <board.h>
12 
13 #ifdef BSP_USING_IRRX
14 
15 //#define DRV_DEBUG
16 #define LOG_TAG             "drv.irrx"
17 #include <drv_log.h>
18 
19 #ifdef BSP_USING_TIM3
20 #error "IRRX is conflict with hardware timer3!"
21 #endif
22 
23 #ifdef BSP_USING_IRRX_HW
24 ///硬件IR receiver参数
25 #define IR32KSEL_EN         0                     //IR clock source select 32K
26 #if IR32KSEL_EN
27     #define RPTERR_CNT      33                    //配置11.25ms ± (RPTERR_CNT + 1)*32K的repeat code允许范围
28     #define DATERR_CNT      33                    //配置13.5ms ± (DATERR_CNT + 1)*32K引导码允许范围
29     #define ONEERR_CNT      7                     //配置2.25ms ± (ONEERR_CNT + 1)*32K的logic "1"允许范围
30     #define ZEROERR_CNT     3                     //配置1.12ms ± (ONEERR_CNT + 1)*32K数logic "0"允许范围
31     #define TOPR_CNT        55                    //IR time out length = (TOPR + 1) * 64 *32K
32 #else
33     #define RPTERR_CNT      1000                  //配置11.25ms ± (RPTERR_CNT + 1)us的repeat code允许范围
34     #define DATERR_CNT      1000                  //配置13.5ms ± (DATERR_CNT + 1)us引导码允许范围
35     #define ONEERR_CNT      250                   //配置2.25ms ± (ONEERR_CNT + 1)us的logic "1"允许范围
36     #define ZEROERR_CNT     125                   //配置1.12ms ± (ONEERR_CNT + 1)us数logic "0"允许范围
37     #define TOPR_CNT        1718                  //IR time out length = (TOPR + 1) * 64 us
38 #endif // IR32KSEL_EN
39 #endif // BSP_USING_IRRX_HW
40 
41 #define NO_KEY      (0u)
42 
43 struct ab32_irrx_data{
44     rt_uint16_t cnt;                            //ir data bit counter
45     rt_uint16_t rpt_cnt;                        //ir repeat counter
46     rt_uint16_t addr;                           //address,  inverted address   Extended NEC: 16bits address
47     rt_uint16_t cmd;                            //command,  inverted command
48 };
49 typedef struct ab32_irrx_data *ab32_irrx_data_t;
50 
51 static struct ab32_irrx_data _irrx = {0};
52 
53 /**
54  * @brief A non-zero value is returned
55  *        when IR key is detectedto be pressed.
56  *
57  * @param addr inverted address   Extended NEC: 16bits address
58  * @param cmd  inverted command
59  */
60 rt_section(".irq.irrx")
ab32_get_irkey(rt_uint16_t * addr,rt_uint16_t * cmd)61 rt_uint8_t ab32_get_irkey(rt_uint16_t *addr, rt_uint16_t *cmd)
62 {
63     if (_irrx.cnt != 32) {
64         return NO_KEY;
65     }
66     if (addr != RT_NULL) {
67         *addr = _irrx.addr;
68     }
69     if (cmd != RT_NULL) {
70         *cmd = _irrx.cmd;
71     }
72     return !NO_KEY;
73 }
74 
75 /**
76  * @brief Invalid the current IR key.
77  *
78  */
ab32_clr_irkey(void)79 void ab32_clr_irkey(void)
80 {
81     _irrx.cnt = 0;
82 }
83 
84 #ifdef BSP_USING_IRRX_HW
85 rt_section(".irq.irrx")
irrx_isr(int vector,void * param)86 static void irrx_isr(int vector, void *param)
87 {
88     rt_interrupt_enter();
89 
90     //IR RX data finish interrupt
91     if (IRRXCON & BIT(16)) {
92         IRRXCPND = BIT(16);
93         _irrx.addr = (rt_uint16_t)IRRXDAT;
94         _irrx.cmd = (rt_uint16_t)(IRRXDAT >> 16);
95         _irrx.cnt = 32;
96     }
97 
98     //IR key release interrupt
99     if (IRRXCON & BIT(17)) {
100         IRRXCPND = BIT(17);
101         _irrx.cnt = 0;
102     }
103 
104     rt_interrupt_leave();
105 }
106 
_irrx_hw_init(void)107 static void _irrx_hw_init(void)
108 {
109     GPIOEDE |= BIT(6);
110     GPIOEPU |= BIT(6);
111     GPIOEDIR |= BIT(6);
112     FUNCMCON2 |= 0xf << 20;
113     FUNCMCON2 |= (7 << 20);                         //IR mapping to G6
114     rt_memset(&_irrx, 0, sizeof(_irrx));
115 
116     IRRXERR0 = (RPTERR_CNT << 16) | DATERR_CNT;     //RPTERR[27:16], DATERR[11:0]
117     IRRXERR1 = (TOPR_CNT << 20) | (ONEERR_CNT << 10) | ZEROERR_CNT;    //TOPR[31:20], ONEERR[19:10], ZEROERR[9:0]
118 
119 #if IR32KSEL_EN
120     CLKCON1 &= ~BIT(5);
121     CLKCON1 |= BIT(4);                              //enable 26M分频32K
122     IRRXCON |= BIT(3);                              //ir clock source select 32K
123 #endif // IR32KSEL_EN
124 
125     rt_hw_interrupt_install(IRQ_IRRX_VECTOR, irrx_isr, RT_NULL, "irrx_isr");
126     IRRXCON = 0x03;
127 
128     // LOG_D("IRRXCON:%08x", IRRXCON);
129 }
130 #endif
131 
132 #ifdef BSP_USING_IRRX_SW
133 
134 #define TMR3_RCLK               (1000u)            //xosc26m_div 1M
135 
136 rt_section(".irq.irrx")
irrx_isr(int vector,void * param)137 static void irrx_isr(int vector, void *param)
138 {
139     rt_uint32_t tmrcnt;
140 
141     if (TMR3CON & BIT(17)) {
142         //timer1 capture interrupt
143         TMR3CNT  = TMR3CNT - TMR3CPT;
144         tmrcnt = TMR3CPT;
145         TMR3CPND = BIT(17);
146         tmrcnt /= TMR3_RCLK;                //convert to ms
147     } else if (TMR3CON & BIT(16)){
148         //timer1 overflow interrupt
149         TMR3CPND = BIT(16);
150         tmrcnt = 110;                   //110ms overflow
151     } else {
152         return;
153     }
154 
155     //processing repeat code
156     if (_irrx.cnt == 32) {
157         if ((tmrcnt >= 10) && (tmrcnt <= 12)) {
158             //repeat code is simply 9ms+2.25ms
159             _irrx.rpt_cnt = 0;
160         } else {
161             _irrx.rpt_cnt += tmrcnt;
162             if (_irrx.rpt_cnt > 108) {
163                 _irrx.rpt_cnt = 0;
164                 _irrx.cnt = 0;          //ir key release
165             }
166         }
167         return;
168     } else if ((tmrcnt > 7) || (tmrcnt == 0)) {     //A message is started by a 9ms AGC burst
169         _irrx.rpt_cnt = 0;
170         _irrx.cnt = 0;                  //ir key message started
171         return;
172     }
173 
174     _irrx.cmd >>= 1;
175     _irrx.cnt++;
176     if (tmrcnt == 2) {                  //Bit time of 1.125ms(0) or 2.25ms(1)
177         _irrx.cmd |= 0x8000;
178     }
179 
180     if (_irrx.cnt == 16) {
181         _irrx.addr = _irrx.cmd;         //save address data
182     } else if (_irrx.cnt == 32) {
183         //got ir key message
184         if ((rt_uint8_t)_irrx.cmd > 96) {
185             _irrx.cmd = NO_KEY;
186         }
187     }
188 }
189 
timer3_init(void)190 static void timer3_init(void)
191 {
192     rt_hw_interrupt_install(IRQ_IRRX_VECTOR, irrx_isr, RT_NULL, "irrx_isr");
193     TMR3CNT  = 0;
194     TMR3PR   = TMR3_RCLK*110 - 1;                                //110ms Timer overflow interrupt
195     TMR3CON  = BIT(8) | BIT(7) | BIT(5) | BIT(2) | BIT(1) | BIT(0);   //capture & overflow interrupt enable, falling edge, Capture Mode
196 }
197 
_irrx_hw_init(void)198 static void _irrx_hw_init(void)
199 {
200     GPIOEDE |= BIT(6);
201     GPIOEPU |= BIT(6);
202     GPIOEDIR |= BIT(6);
203     FUNCMCON2 |= 0xf << 4;
204     FUNCMCON2 |= (7 << 4);                              // timer3 G6 PE6 capture
205     rt_memset(&_irrx, 0, sizeof(_irrx));
206 
207     timer3_init();
208 }
209 #endif
210 
ab32_irrx_init(void)211 static int ab32_irrx_init(void)
212 {
213     _irrx_hw_init();
214     LOG_D("irrx init success");
215     return RT_EOK;
216 }
217 INIT_BOARD_EXPORT(ab32_irrx_init);
218 
219 #endif
220