1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2022-07-15     Emuzit            first version
9  * 2022-07-20     Emuzit            add watchdog test
10  * 2022-07-26     Emuzit            add hwtimer test
11  * 2022-07-30     Emuzit            add spi master test
12  * 2022-08-04     Emuzit            add pwm test
13  */
14 #include <rtthread.h>
15 #include <drivers/dev_pin.h>
16 #include "drivers/dev_watchdog.h"
17 #include <drivers/hwtimer.h>
18 #include "drivers/dev_spi.h"
19 #include <drivers/dev_pwm.h>
20 #include "board.h"
21 
22 #define PWM_CYCLE_MAX   255
23 
24 static const rt_base_t gpio_int_pins[8] = GPIO_INT_PINS;
25 
26 /* note : PIN_IRQ_MODE_RISING_FALLING not supported */
27 static const uint32_t gpint_mode[] =
28 {
29     PIN_IRQ_MODE_RISING,
30     PIN_IRQ_MODE_RISING,
31     PIN_IRQ_MODE_RISING,
32     PIN_IRQ_MODE_RISING,
33     PIN_IRQ_MODE_FALLING,
34     PIN_IRQ_MODE_FALLING,
35     PIN_IRQ_MODE_FALLING,
36     PIN_IRQ_MODE_FALLING,
37 };
38 
39 static struct rt_mailbox *gpint_mb = RT_NULL;
40 static struct rt_thread  *gpint_thread = RT_NULL;
41 
42 static rt_device_t wdg_dev;
43 
44 static rt_base_t led0, led1;
45 
gpio_int_callback(void * pin)46 static void gpio_int_callback(void *pin)
47 {
48     led1 = (led1 == PIN_LOW) ? PIN_HIGH : PIN_LOW;
49     rt_pin_write(LED1_PIN, led1);
50 
51     if (gpint_mb != RT_NULL)
52     {
53         /* non-block, silently ignore RT_EFULL */
54         rt_mb_send(gpint_mb, (uint32_t)pin);
55     }
56 }
57 
gpio_int_thread(void * param)58 static void gpio_int_thread(void *param)
59 {
60     while (1)
61     {
62         rt_err_t res;
63         uint32_t pin;
64 
65         res = rt_mb_recv(gpint_mb, &pin, RT_WAITING_FOREVER);
66         if (res == RT_EOK)
67         {
68             rt_kprintf("gpio_int #%d (%d)\n", pin, rt_pin_read(pin));
69         }
70         rt_thread_mdelay(100);
71 
72 #ifdef RT_USING_WDT
73         rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, RT_NULL);
74 #endif
75     }
76 }
77 
test_gpio_int(void)78 static void test_gpio_int(void)
79 {
80     rt_err_t res;
81     int i;
82 
83     rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
84     rt_pin_write(LED1_PIN, led1 = PIN_HIGH);
85 
86     /* Enable all gpio interrupt with various modes.
87      * LED0 or GND touching can be used to trigger pin interrupt.
88     */
89     gpint_mb = rt_mb_create("pximb", 8, RT_IPC_FLAG_FIFO);
90     if (gpint_mb == RT_NULL)
91     {
92         rt_kprintf("gpint mailbox create failed !\n");
93     }
94     else
95     {
96         gpint_thread = rt_thread_create("pxith", gpio_int_thread, RT_NULL,
97                                         512, RT_MAIN_THREAD_PRIORITY, 50);
98         if (gpint_thread == RT_NULL)
99         {
100             rt_kprintf("gpint thread create failed !\n");
101         }
102         else
103         {
104             rt_thread_startup(gpint_thread);
105 
106             for (i = 0; i < 8; i++)
107             {
108                 rt_base_t pin = gpio_int_pins[i];
109 #ifdef RT_USING_PWM
110                 if (pin == PWM0_PIN || pin == PWM1_PIN)
111                     continue;
112 #endif
113                 rt_pin_mode(pin, PIN_MODE_INPUT_PULLUP);
114                 res = rt_pin_attach_irq(
115                       pin, gpint_mode[i], gpio_int_callback, (void *)pin);
116                 if (res != RT_EOK)
117                 {
118                     rt_kprintf("rt_pin_attach_irq failed (%d:%d)\n", i, res);
119                 }
120                 else
121                 {
122                     rt_pin_irq_enable(pin, PIN_IRQ_ENABLE);
123                 }
124             }
125         }
126     }
127 }
128 
129 #ifdef RT_USING_WDT
test_watchdog(uint32_t seconds)130 static void test_watchdog(uint32_t seconds)
131 {
132     /* Test watchdog with 30s timeout, keepalive with gpio interrupt.
133      *
134      * CAVEAT: With only 8-bit WDOG_COUNT and fixed clocking at Fsys/524288,
135      * watchdog of ch56x may be quite limited with very short timeout.
136     */
137     seconds = 30;
138     wdg_dev = rt_device_find("wdt");
139     if (!wdg_dev)
140     {
141         rt_kprintf("watchdog device not found !\n");
142     }
143     else if (rt_device_init(wdg_dev) != RT_EOK ||
144              rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &seconds) != RT_EOK)
145     {
146         rt_kprintf("watchdog setup failed !\n");
147     }
148     else
149     {
150         rt_kprintf("WDT_TIMEOUT in %d seconds, trigger gpio interrupt to keep alive.\n\n", seconds);
151     }
152 }
153 #else
154     #define test_watchdog(tov)  do {} while(0)
155 #endif
156 
157 #ifdef RT_USING_HWTIMER
158 static struct rt_device *tmr_dev_0;
159 static struct rt_device *tmr_dev_1;
160 
tmr_timeout_cb(rt_device_t dev,rt_size_t size)161 static rt_err_t tmr_timeout_cb(rt_device_t dev, rt_size_t size)
162 {
163     rt_tick_t tick = rt_tick_get();
164 
165     int tmr = (dev == tmr_dev_1) ? 1 : 0;
166 
167     rt_kprintf("hwtimer %d timeout callback fucntion @tick %d\n", tmr, tick);
168 
169     return RT_EOK;
170 }
171 
test_hwtimer(void)172 static void test_hwtimer(void)
173 {
174     rt_hwtimerval_t timerval;
175     rt_hwtimer_mode_t mode;
176     rt_size_t tsize;
177 
178     /* setup two timers, ONESHOT & PERIOD each
179     */
180     tmr_dev_0 = rt_device_find("timer0");
181     tmr_dev_1 = rt_device_find("timer1");
182     if (tmr_dev_0 == RT_NULL || tmr_dev_1 == RT_NULL)
183     {
184         rt_kprintf("hwtimer device(s) not found !\n");
185     }
186     else if (rt_device_open(tmr_dev_0, RT_DEVICE_OFLAG_RDWR) != RT_EOK ||
187              rt_device_open(tmr_dev_1, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
188     {
189         rt_kprintf("hwtimer device(s) open failed !\n");
190     }
191     else
192     {
193         rt_device_set_rx_indicate(tmr_dev_0, tmr_timeout_cb);
194         rt_device_set_rx_indicate(tmr_dev_1, tmr_timeout_cb);
195 
196         timerval.sec = 3;
197         timerval.usec = 500000;
198         tsize = sizeof(timerval);
199         mode = HWTIMER_MODE_ONESHOT;
200         if (rt_device_control(tmr_dev_0, HWTIMER_CTRL_MODE_SET, &mode) != RT_EOK)
201         {
202             rt_kprintf("timer0 set mode failed !\n");
203         }
204         else if (rt_device_write(tmr_dev_0, 0, &timerval, tsize) != tsize)
205         {
206             rt_kprintf("timer0 start failed !\n");
207         }
208         else
209         {
210             rt_kprintf("timer0 started !\n");
211         }
212 
213         timerval.sec = 5;
214         timerval.usec = 0;
215         tsize = sizeof(timerval);
216         mode = HWTIMER_MODE_PERIOD;
217         if (rt_device_control(tmr_dev_1, HWTIMER_CTRL_MODE_SET, &mode) != RT_EOK)
218         {
219             rt_kprintf("timer1 set mode failed !\n");
220         }
221         else if (rt_device_write(tmr_dev_1, 0, &timerval, tsize) != tsize)
222         {
223             rt_kprintf("timer1 start failed !\n");
224         }
225         else
226         {
227             rt_kprintf("timer1 started !\n\n");
228         }
229     }
230 }
231 #else
232     #define test_hwtimer()  do {} while(0)
233 #endif
234 
235 #ifdef RT_USING_SPI
236 static struct rt_spi_device spi_dev_w25q;
237 
test_spi_master(void)238 static void test_spi_master(void)
239 {
240     struct rt_spi_configuration cfg;
241     struct rt_spi_message msg1, msg2;
242     rt_err_t res;
243 
244     uint8_t buf[16];
245     int i;
246 
247     cfg.max_hz = 25 * 1000000;
248     cfg.data_width = 8;
249     cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
250 
251     res = rt_spi_bus_attach_device(
252           &spi_dev_w25q, W25Q32_SPI_NAME, SPI0_BUS_NAME, (void *)W25Q32_CS_PIN);
253     if (res == RT_EOK && rt_spi_configure(&spi_dev_w25q, &cfg) == RT_EOK)
254     {
255         /* cmd : Read Manufacturer / Device ID (90h) */
256         buf[0] = 0x90;
257         /* address : 0 */
258         buf[1] = buf[2] = buf[3] = 0;
259         msg1.send_buf   = buf;
260         msg1.recv_buf   = RT_NULL;
261         msg1.length     = 4;
262         msg1.cs_take    = 1;
263         msg1.cs_release = 0;
264         msg1.next       = &msg2;
265 
266         msg2.send_buf   = RT_NULL;
267         msg2.recv_buf   = buf;
268         msg2.length     = 2;
269         msg2.cs_take    = 0;
270         msg2.cs_release = 1;
271         msg2.next       = RT_NULL;
272 
273         rt_spi_transfer_message(&spi_dev_w25q, &msg1);
274         rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%x%x\n", buf[0], buf[1]);
275 
276         /* cmd : Read Data (03h)  */
277         buf[0] = 0x03;
278         /* address : 0 */
279         buf[1] = buf[2] = buf[3] = 0;
280         msg2.length = 16;
281         if (rt_spi_transfer_message(&spi_dev_w25q, &msg1) == RT_NULL)
282         {
283             rt_kprintf("SPI0 16-byte DMA read :");
284             for (i = 0; i < 16; i++)
285                 rt_kprintf(" %02x", buf[i]);
286             rt_kprintf("\n\n");
287         }
288     }
289     else
290     {
291         rt_kprintf("w25q32 attach/configure failed (%d) !\n", res);
292     }
293 }
294 #else
295     #define test_spi_master()  do {} while(0)
296 #endif
297 
298 #ifdef RT_USING_PWM
299 static struct rt_device_pwm *pwm_dev;
300 static uint32_t pwm_period;
301 
302 rt_err_t rt_pwm_get(struct rt_device_pwm *device,
303                     struct rt_pwm_configuration *cfg);
304 
pwm_tick_hook(void)305 static void pwm_tick_hook(void)
306 {
307     uint32_t pulse;
308 
309     if (pwm_dev)
310     {
311         /* PWM.CH3 duty cycle : 0%->100% for every ~2.5 seconds */
312         pulse = (rt_tick_get() >> 1) % (PWM_CYCLE_MAX + 1);
313         pulse = (pwm_period * pulse + PWM_CYCLE_MAX/2) / PWM_CYCLE_MAX;
314         rt_pwm_set_pulse(pwm_dev, 3, pulse);
315     }
316 }
317 
test_pwm(void)318 static void test_pwm(void)
319 {
320     struct rt_pwm_configuration cfg;
321     uint32_t pulse[4];
322     int ch;
323 
324     pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEVICE_NAME);
325     if (pwm_dev == RT_NULL)
326     {
327         rt_kprintf("can't find %s device !\n", PWM_DEVICE_NAME);
328     }
329     else
330     {
331         /* for HCLK@80MHz, allowed period is 3187 ~ 812812 */
332         pwm_period = 800*1000;
333 
334         pulse[0] = 100*1000;
335         pulse[1] = 400*1000;
336         pulse[2] = 600*1000;
337         pulse[3] = 0;
338 
339         for (ch = 0; ch < PWM_CHANNELS; ch++)
340         {
341             rt_pwm_set(pwm_dev, ch, pwm_period, pulse[ch]);
342             rt_pwm_enable(pwm_dev, ch);
343 
344             cfg.channel = ch;
345             rt_pwm_get(pwm_dev, &cfg);
346             rt_kprintf("pwm%d period set/get : %d/%d\n", ch, pwm_period, cfg.period);
347             rt_kprintf("pwm%d pulse  set/get : %d/%d\n\n", ch, pulse[ch], cfg.pulse);
348         }
349 
350         /* disable PWM.CH0 after 1 second, also start changing CH3 */
351         rt_thread_mdelay(1000);
352         rt_pwm_disable(pwm_dev, 0);
353 
354         /* connect PWM3 (PB.2) to LED2 for a visualized PWM effect */
355         rt_pin_mode(LED2_PIN, PIN_MODE_INPUT);
356         rt_tick_sethook(pwm_tick_hook);
357     }
358 }
359 #else
360     #define test_pwm()  do {} while(0)
361 #endif
362 
363 #ifdef RT_USING_USB_DEVICE
364 #if !defined(RT_USING_EVENT) || !defined(RT_USING_MESSAGEQUEUE)
365     #error "event flag or message queue IPC not enabled"
366 #endif
367 static struct rt_thread  *udvcom_thread;
368 static rt_device_t vcom;
369 
usbd_vcom_thread(void * param)370 static void usbd_vcom_thread(void *param)
371 {
372     char ch;
373 
374     while (1)
375     {
376         while (rt_device_read(vcom, 0, &ch, 1) != 1)
377             rt_thread_delay(1);
378         rt_kprintf("(%2d) %02x:%c\n", rt_device_write(vcom, 0, &ch, 1), ch, ch);
379         rt_pin_write(LED1_PIN, (ch & 1) ? PIN_LOW : PIN_HIGH);
380     }
381 }
382 
test_usbd()383 static void test_usbd()
384 {
385     char name[] = "vcom";
386 
387     vcom = rt_device_find(name);
388     if (vcom && rt_device_open(vcom, RT_DEVICE_FLAG_INT_RX) == RT_EOK)
389     {
390         rt_kprintf("%s opened\n", name);
391 
392         rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
393         rt_pin_write(LED1_PIN, PIN_LOW);
394 
395         udvcom_thread = rt_thread_create("udvcom", usbd_vcom_thread, vcom,
396                                          512, 20, 50);
397         if (udvcom_thread != RT_NULL)
398             rt_thread_startup(udvcom_thread);
399         else
400             rt_kprintf("usvcom thread create failed !\n");
401 
402         rt_device_write(vcom, 0, name, rt_strlen(name));
403     }
404 }
405 #else
406     #define test_usbd()  do {} while(0)
407 #endif
408 
main(void)409 void main(void)
410 {
411     uint32_t wdog_timeout = 32;
412 
413     rt_kprintf("\nCH569W-R0-1v0, HCLK: %dMHz\n\n", sys_hclk_get() / 1000000);
414 
415     test_gpio_int();
416     test_watchdog(wdog_timeout);
417     test_hwtimer();
418     test_spi_master();
419     test_pwm();
420     test_usbd();
421 
422     rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
423     rt_pin_write(LED0_PIN, led0 = PIN_LOW);
424 
425     while (1)
426     {
427         /* flashing LED0 every 1 second */
428         rt_thread_mdelay(500);
429         led0 = (led0 == PIN_LOW) ? PIN_HIGH : PIN_LOW;
430         rt_pin_write(LED0_PIN, led0);
431     }
432 }
433