Reformat.
[bertos.git] / boards / sam3x-ek / examples / sam3x-ek_display / main.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Atmel SAM3X-EK testcase
34  *
35  * \author Stefano Fedrigo <aleph@develer.com>
36  */
37
38 #include "bitmaps.h"
39
40 #include "hw/hw_led.h"
41 #include "hw/hw_lcd.h"
42 #include "hw/hw_adc.h"
43 #include "hw/hw_sdram.h"
44
45 #include <cfg/debug.h>
46
47 #include <cpu/irq.h>
48
49 #include <struct/heap.h>
50
51 #include <drv/timer.h>
52 #include <drv/kbd.h>
53 #include <drv/lcd_hx8347.h>
54 #include <drv/adc.h>
55
56 #include <gfx/gfx.h>
57 #include <gfx/font.h>
58 #include <gfx/text.h>
59 #include <gui/menu.h>
60 #include <icons/logo.h>
61
62 #include <io/kfile.h>
63
64 #include <kern/signal.h>
65 #include <kern/proc.h>
66
67
68 // Keyboard
69 #define KEY_MASK (K_LEFT | K_RIGHT)
70
71 // Kernel
72 #define PROC_STACK_SIZE KERN_MINSTACKSIZE * 2
73
74 #if CONFIG_KERN_HEAP
75         #define hp_stack NULL
76         #define lp_stack NULL
77         #define led_stack NULL
78 #else
79         static PROC_DEFINE_STACK(hp_stack, PROC_STACK_SIZE);
80         static PROC_DEFINE_STACK(lp_stack, PROC_STACK_SIZE);
81         static PROC_DEFINE_STACK(led_stack, PROC_STACK_SIZE);
82 #endif
83
84 static struct Heap heap;
85 static uint8_t raster[RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)];
86 static Bitmap *lcd_bitmap;
87 extern Font font_gohu;
88 static int lcd_brightness = LCD_BACKLIGHT_MAX;
89 static Process *hp_proc, *lp_proc, *led_proc;
90 static hptime_t start, end;
91
92
93 static bool led_blinking;
94
95 static void NORETURN led_process(void)
96 {
97         unsigned i;
98
99         for (i = 0; ; i++)
100         {
101                 if (!led_blinking)
102                 {
103                         LED_OFF(0);
104                         LED_OFF(1);
105                         LED_OFF(2);
106                         sig_wait(SIG_USER0);
107                 }
108                 LED_ON(i % 3);
109                 LED_OFF((i-1) % 3);
110                 timer_delay(200);
111         }
112 }
113
114 static void led_test(UNUSED_ARG(Bitmap *, bm))
115 {
116         led_blinking = !led_blinking;
117         sig_send(led_proc, SIG_USER0);
118 }
119
120 static void bouncing_logo(Bitmap *bm)
121 {
122         const long SPEED_SCALE = 1000;
123         const long GRAVITY_ACCEL = 100;
124         const long BOUNCE_ELASTICITY = 1;
125         long h = (long)(-bertos_logo.height) * SPEED_SCALE;
126         long speed = 0, i;
127
128         for (i = 0; ; i++)
129         {
130                 /* Move */
131                 h += speed;
132
133                 /* Gravity acceleration */
134                 speed += GRAVITY_ACCEL;
135
136                 if (h > 0 && speed > 0)
137                 {
138                         /* Bounce */
139                         speed = -(speed / BOUNCE_ELASTICITY);
140
141                 }
142                 /* Update graphics */
143                 gfx_bitmapClear(bm);
144                 gfx_blitImage(bm,
145                         (LCD_WIDTH - bertos_logo.width) / 2,
146                         (LCD_HEIGHT - bertos_logo.height) / 2 + h / SPEED_SCALE,
147                         &bertos_logo);
148                 text_xprintf(bm, 13, 0, TEXT_FILL | TEXT_CENTER, "Press any key to quit");
149                 lcd_hx8347_blitBitmap(bm);
150                 timer_delay(15);
151                 if (kbd_peek() & KEY_MASK)
152                         break;
153         }
154 }
155
156 static void screen_saver(Bitmap *bm)
157 {
158         int x1, y1, x2, y2;
159         int i;
160
161         for (i = 0; ; i++)
162         {
163                 x1 = i % LCD_WIDTH;
164                 y1 = i % LCD_HEIGHT;
165
166                 x2 = LCD_WIDTH - i % LCD_WIDTH;
167                 y2 = LCD_HEIGHT - i % LCD_HEIGHT;
168
169                 gfx_bitmapClear(bm);
170                 gfx_rectDraw(bm, x1, y1, x2, y2);
171                 lcd_hx8347_blitBitmap(bm);
172                 if (kbd_peek() & KEY_MASK)
173                         break;
174         }
175 }
176
177 static void show_logo(UNUSED_ARG(Bitmap *, bm))
178 {
179         lcd_hx8347_blitBitmap24(10, 52, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, bmp_logo);
180
181         while (!(kbd_peek() & KEY_MASK))
182                 timer_delay(50);
183 }
184
185
186 INLINE hptime_t get_hp_ticks(void)
187 {
188         return (timer_clock_unlocked() * TIMER_HW_CNT) + timer_hw_hpread();
189 }
190
191 static void NORETURN hp_process(void)
192 {
193         while (1)
194         {
195                 sig_wait(SIG_USER0);
196                 end = get_hp_ticks();
197                 timer_delay(100);
198                 sig_send(lp_proc, SIG_USER0);
199         }
200 }
201
202 static void NORETURN lp_process(void)
203 {
204         while (1)
205         {
206                 start = get_hp_ticks();
207                 sig_send(hp_proc, SIG_USER0);
208                 sig_wait(SIG_USER0);
209         }
210 }
211
212 static void res_process(void)
213 {
214         const char spinner[] = {'/', '-', '\\', '|'};
215         int i;
216         char c;
217
218         for (i = 0; ; i++)
219         {
220                 /* Show context switch (in clock cycles) */
221                 c = spinner[i % countof(spinner)];
222                 text_xprintf(lcd_bitmap, 3, 0, TEXT_CENTER | TEXT_FILL, "%c Context switch %c", c, c);
223                 text_xprintf(lcd_bitmap, 5, 0, TEXT_FILL, " %lu clock cycles", end - start);
224                 /* Show context switch (in usec) */
225                 text_xprintf(lcd_bitmap, 6, 0, TEXT_FILL,
226                         " %lu.%lu usec",
227                                 ((end - start) * 1000000) / CPU_FREQ,
228                                 ((end - start) * (100000000 / CPU_FREQ)) % 100);
229                 text_xprintf(lcd_bitmap, 8, 0, TEXT_FILL,
230                         " Free heap memory: %u bytes", heap_freeSpace(&heap));
231                 lcd_hx8347_blitBitmap(lcd_bitmap);
232                 timer_delay(5);
233                 if (kbd_peek() & KEY_MASK)
234                         break;
235         }
236 }
237
238 static void context_switch_test(Bitmap *bm)
239 {
240         const Font *old_font = bm->font;
241         gfx_setFont(lcd_bitmap, &font_gohu);
242
243         gfx_bitmapClear(bm);
244         text_xprintf(bm, 0, 0, TEXT_FILL,
245                         "CPU: Cortex-M3 %luMHz", CPU_FREQ / 1000000);
246         text_xprintf(bm, 1, 0, TEXT_FILL, "Board: SAM3X-EK EVB");
247
248         res_process();
249
250         gfx_setFont(lcd_bitmap, old_font);
251 }
252
253 static void uptime(Bitmap *bm)
254 {
255         gfx_bitmapClear(bm);
256         text_xprintf(bm, 0, 0, TEXT_FILL | TEXT_CENTER, "Uptime");
257         while (1)
258         {
259                 ticks_t clock = ticks_to_ms(timer_clock_unlocked());
260
261                 /* Display uptime (in ticks) */
262                 text_xprintf(lcd_bitmap, 2, 0, TEXT_FILL | TEXT_CENTER,
263                                 "seconds: %lu", clock / 1000);
264                 lcd_hx8347_blitBitmap(bm);
265                 timer_delay(5);
266                 if (kbd_peek() & KEY_MASK)
267                         break;
268         }
269 }
270
271 /*
272  * Lcd
273  */
274 static void setBrightness(Bitmap *bm)
275 {
276         while (1)
277         {
278                 gfx_bitmapClear(bm);
279                 text_xprintf(bm, 1, 0, TEXT_FILL | TEXT_CENTER, "Brightness: %d", lcd_brightness);
280                 text_xprintf(bm, 3, 0, TEXT_FILL | TEXT_CENTER, "RIGHT key: change");
281                 text_xprintf(bm, 4, 0, TEXT_FILL | TEXT_CENTER, "LEFT  key: back  ");
282                 lcd_hx8347_blitBitmap(bm);
283
284                 keymask_t mask = kbd_get();
285
286                 if (mask & K_LEFT)
287                         break;
288                 else if (mask & K_RIGHT)
289                 {
290                         if (++lcd_brightness > LCD_BACKLIGHT_MAX)
291                                 lcd_brightness = 0;
292                         lcd_setBacklight(lcd_brightness);
293                 }
294         }
295 }
296
297
298 static void NORETURN soft_reset(Bitmap * bm)
299 {
300         int i;
301
302         gfx_bitmapClear(bm);
303         for (i = 5; i; --i)
304         {
305                 text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "%d", i);
306                 lcd_hx8347_blitBitmap(bm);
307                 timer_delay(1000);
308         }
309         text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "REBOOT");
310         lcd_hx8347_blitBitmap(bm);
311         timer_delay(1000);
312
313         /* Perform a software reset request */
314         HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ;
315         UNREACHABLE();
316 }
317
318 static void read_adc(Bitmap *bm)
319 {
320         gfx_bitmapClear(bm);
321         text_xprintf(bm, 0, 0, TEXT_FILL | TEXT_CENTER, "ADC Value");
322         while (1)
323         {
324                 uint16_t value = ADC_RANGECONV(adc_read(1), 0, 3300);
325                 uint16_t temp = hw_convertToDegree(adc_read(ADC_TEMPERATURE_CH));
326
327                 text_xprintf(lcd_bitmap, 2, 0, TEXT_FILL | TEXT_CENTER,
328                                                                         "Voltage on VR1: %d.%dV", value / 1000, value % 1000);
329                 text_xprintf(lcd_bitmap, 3, 0, TEXT_FILL | TEXT_CENTER,
330                                                                         "CPU temperature: %d.%dC", temp / 10, temp % 10);
331                 lcd_hx8347_blitBitmap(bm);
332                 timer_delay(400);
333                 if (kbd_peek() & KEY_MASK)
334                         break;
335         }
336 }
337
338
339 static struct MenuItem main_items[] =
340 {
341         { (const_iptr_t)"LED blinking", 0, (MenuHook)led_test, NULL },
342         { (const_iptr_t)"Graphics demo", 0, (MenuHook)show_logo, NULL },
343         { (const_iptr_t)"Bouncing logo", 0, (MenuHook)bouncing_logo, NULL },
344         { (const_iptr_t)"Screen saver demo", 0, (MenuHook)screen_saver, NULL },
345         { (const_iptr_t)"Scheduling test", 0, (MenuHook)context_switch_test, NULL },
346         { (const_iptr_t)"Show uptime", 0, (MenuHook)uptime, NULL },
347         { (const_iptr_t)"Display brightness", 0, (MenuHook)setBrightness, NULL },
348         { (const_iptr_t)"ADC demo", 0, (MenuHook)read_adc, NULL },
349         { (const_iptr_t)"Reboot", 0, (MenuHook)soft_reset, NULL },
350         { (const_iptr_t)0, 0, NULL, (iptr_t)0 }
351 };
352 static struct Menu main_menu = { main_items, "BeRTOS", MF_STICKY | MF_SAVESEL, NULL, 0, lcd_hx8347_blitBitmap };
353
354
355 int main(void)
356 {
357         unsigned i;
358
359         IRQ_ENABLE;
360         kdbg_init();
361         LED_INIT();
362         timer_init();
363         proc_init();
364         sdram_init();
365         adc_init();
366
367         /* Enable the adc to read internal temperature sensor */
368         hw_enableTempRead();
369
370         heap_init(&heap, (void *)SDRAM_BASE, SDRAM_SIZE);
371         lcd_bitmap = heap_allocmem(&heap, RAST_SIZE(LCD_WIDTH, LCD_HEIGHT));
372         if (lcd_bitmap)
373                 kprintf("Allocated memory for display raster, addr 0x%x\n", (unsigned)lcd_bitmap);
374         else
375         {
376                 kprintf("Error allocating memory for LCD raster!\n");
377                 return 0;
378         }
379         for (i = 0; main_items[i].label; i++)
380                 main_items[i].userdata = lcd_bitmap;
381         main_menu.bitmap = lcd_bitmap;
382
383         lcd_hx8347_init();
384         lcd_setBacklight(lcd_brightness);
385
386         gfx_bitmapInit(lcd_bitmap, raster, LCD_WIDTH, LCD_HEIGHT);
387         gfx_setFont(lcd_bitmap, &font_luBS14);
388         lcd_hx8347_blitBitmap(lcd_bitmap);
389
390         kbd_init();
391
392         hp_proc = proc_new(hp_process, NULL, PROC_STACK_SIZE, hp_stack);
393         lp_proc = proc_new(lp_process, NULL, PROC_STACK_SIZE, lp_stack);
394         led_proc = proc_new(led_process, NULL, PROC_STACK_SIZE, led_stack);
395
396         proc_setPri(hp_proc, 2);
397         proc_setPri(lp_proc, 1);
398
399         lcd_hx8347_blitBitmap24(10, 52, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, bmp_logo);
400         timer_delay(3000);
401
402         while (1)
403         {
404                 menu_handle(&main_menu);
405                 cpu_relax();
406         }
407
408 }