4 * This file is part of BeRTOS.
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.
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.
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
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.
29 * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
33 * \brief Atmel SAM3X-EK testcase
35 * \author Stefano Fedrigo <aleph@develer.com>
40 #include "hw/hw_led.h"
41 #include "hw/hw_lcd.h"
42 #include "hw/hw_adc.h"
43 #include "hw/hw_sdram.h"
46 #include "cfg/cfg_i2s.h"
48 #include <cfg/debug.h>
52 #include <cpu/byteorder.h>
58 #include <drv/timer.h>
59 #include <drv/lcd_hx8347.h>
61 #include <drv/wm8731.h>
62 #include <drv/dmac_sam3.h>
69 #include <icons/logo.h>
72 #include <io/kfile_block.h>
74 #include <kern/signal.h>
75 #include <kern/proc.h>
79 #include <struct/list.h>
87 #define KEY_MASK (K_LEFT | K_RIGHT)
90 #define PROC_STACK_SIZE KERN_MINSTACKSIZE * 2
92 static PROC_DEFINE_STACK(hp_stack, PROC_STACK_SIZE);
93 static PROC_DEFINE_STACK(lp_stack, PROC_STACK_SIZE);
96 * Codec has 7-bit address, the eighth is the R/W bit, so we
97 * write the codec address with one bit shifted left
99 #define CODEC_ADDR 0x36
103 typedef struct WavHdr
109 char subchunk1_id[4];
110 uint32_t subchunk1_size;
111 uint16_t audio_format;
112 uint16_t num_channels;
113 uint32_t sample_rate;
115 uint16_t block_align;
116 uint16_t bits_per_sample;
118 uint8_t subchunk2[8];
122 static uint8_t raster[RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)];
123 static Bitmap lcd_bitmap;
124 extern Font font_gohu;
125 static int lcd_brightness = LCD_BACKLIGHT_MAX;
126 static Process *hp_proc, *lp_proc;
127 static hptime_t start, end;
132 // SD fat filesystem context
139 static Wm8731 wm8731_ctx;
142 static void screen_saver(Bitmap *bm)
152 x2 = LCD_WIDTH - i % LCD_WIDTH;
153 y2 = LCD_HEIGHT - i % LCD_HEIGHT;
156 gfx_rectDraw(bm, x1, y1, x2, y2);
157 lcd_hx8347_blitBitmap(bm);
158 if (kbd_peek() & KEY_MASK)
164 INLINE hptime_t get_hp_ticks(void)
166 return (timer_clock_unlocked() * TIMER_HW_CNT) + timer_hw_hpread();
169 static void NORETURN hp_process(void)
174 end = get_hp_ticks();
176 sig_send(lp_proc, SIG_USER0);
180 static void NORETURN lp_process(void)
184 start = get_hp_ticks();
185 sig_send(hp_proc, SIG_USER0);
193 static void setBrightness(Bitmap *bm)
198 text_xprintf(bm, 1, 0, TEXT_FILL | TEXT_CENTER, "Brightness: %d", lcd_brightness);
199 text_xprintf(bm, 3, 0, TEXT_FILL | TEXT_CENTER, "RIGHT key: change");
200 text_xprintf(bm, 4, 0, TEXT_FILL | TEXT_CENTER, "LEFT key: back ");
201 lcd_hx8347_blitBitmap(bm);
203 keymask_t mask = kbd_get();
207 else if (mask & K_RIGHT)
209 if (++lcd_brightness > LCD_BACKLIGHT_MAX)
211 lcd_setBacklight(lcd_brightness);
217 static void NORETURN soft_reset(Bitmap * bm)
224 text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "%d", i);
225 lcd_hx8347_blitBitmap(bm);
228 text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "REBOOT");
229 lcd_hx8347_blitBitmap(bm);
232 /* Perform a software reset request */
233 HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ;
237 static void read_adc(Bitmap *bm)
240 text_xprintf(bm, 0, 0, TEXT_FILL | TEXT_CENTER, "ADC Value");
243 uint16_t value = ADC_RANGECONV(adc_read(1), 0, 3300);
244 uint16_t temp = hw_convertToDegree (adc_read(ADC_TEMPERATURE_CH));
246 text_xprintf(&lcd_bitmap, 2, 0, TEXT_FILL | TEXT_CENTER,
247 "Voltage on VR1: %d.%dV", value / 1000, value % 1000);
248 text_xprintf(&lcd_bitmap, 3, 0, TEXT_FILL | TEXT_CENTER,
249 "CPU temperature: %d.%dC", temp / 10, temp % 10);
250 lcd_hx8347_blitBitmap(bm);
252 if (kbd_peek() & KEY_MASK)
256 #define FILE_NAME "outfile.wav"
257 #define ACQ_FILE_NAME FILE_NAME
262 // SD fat filesystem context
269 static int wav_check(KFile *fd)
274 if (kfile_read(fd, &header, sizeof(header)) != sizeof(header))
276 kputs("Error reading wave file header\n");
280 if (strncmp(header.chunk_id, "RIFF", 4))
282 kputs("RIFF tag not found\n");
286 if (strncmp(header.format, "WAVE", 4))
288 kputs("WAVE tag not found\n");
292 if (le16_to_cpu(header.audio_format) != 1)
294 kprintf("Audio format not valid, found [%d]\n", le16_to_cpu(header.audio_format));
298 if (le16_to_cpu(header.num_channels) != 2)
300 kprintf("Channels number not valid, found [%d]\n", le16_to_cpu(header.num_channels));
305 if (le32_to_cpu(header.sample_rate) != 44100)
307 kprintf("Sample rate not valid, found [%ld]\n", le32_to_cpu(header.sample_rate));
311 if (le16_to_cpu(header.bits_per_sample) != 16)
313 kprintf("Bits per sample not valid, found [%d]\n", le16_to_cpu(header.bits_per_sample));
323 static int wav_writeHdr(KFile *fd, uint16_t rate, uint16_t channels, uint16_t bits)
327 memcpy(&header.chunk_id, "RIFF", 4);
328 memcpy(&header.format, "WAVE", 4);
329 header.audio_format = cpu_to_le16((uint16_t)1);
330 header.num_channels = cpu_to_le16(channels);
331 header.sample_rate = cpu_to_le16(rate);
332 header.bits_per_sample = cpu_to_le16(bits);
334 kfile_seek(fd, 0, KSM_SEEK_SET);
335 kfile_write(fd, &header, sizeof(header));
341 static void codec_play(struct I2s *i2s, void *_buf, size_t len)
343 count += kfile_read(&log_file.fd, _buf, len);
344 if (count >= log_file.fat_file.fsize - sizeof(WavHdr))
346 kprintf("stop %d\n", count);
352 static void codec_rec(struct I2s *i2s, void *_buf, size_t len)
354 count += kfile_write(&acq_file.fd, _buf, len);
355 if (count >= 1024 * 1024)
357 kprintf("stop %d\n", count);
365 #define MAX_ITEM_NODES 30
366 #define MAX_ITEMS_ROW 15
367 #define NEXT_ITEM_COL 10
369 typedef struct FileItemNode
375 FileItemNode item_nodes[MAX_ITEM_NODES];
378 static void wav_play(Bitmap *bm, char *file_name)
382 kprintf("Mount FAT filesystem.\n");
383 FRESULT result = f_mount(0, &fs);
387 kprintf("Mounting FAT volumes error[%d]\n", result);
393 result = fatfile_open(&log_file, file_name, FA_OPEN_EXISTING | FA_READ);
396 text_xprintf(bm, 1, 0, TEXT_CENTER, "Play wav file: %s", file_name);
397 text_xprintf(bm, 2, 0, TEXT_CENTER, "File: %ld", log_file.fat_file.fsize);
398 text_xprintf(bm, 3, 0, TEXT_CENTER, "Volume level %ld", ADC_RANGECONV(adc_read(1), 0, 100));
399 kprintf("Open file: %s\n", file_name);
400 wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, ADC_RANGECONV(adc_read(1), 0, 100));
402 lcd_hx8347_blitBitmap(bm);
403 if (wav_check(&log_file.fd) >= 0)
405 kputs("Wav file play..\n");
406 i2s_dmaStartTxStreaming(&i2s, tmp, sizeof(tmp), sizeof(tmp) / 4, codec_play);
409 wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0);
411 // Flush data and close the files.
412 kfile_flush(&log_file.fd);
413 kfile_close(&log_file.fd);
417 kprintf("Unable to open file: '%s' error[%d]\n", FILE_NAME, result);
422 lcd_hx8347_blitBitmap(bm);
426 INLINE FileItemNode *refresh_cursor(Bitmap *bm, List *file_list, int select_idx)
429 FileItemNode *select_node;
434 select_node = (FileItemNode *)LIST_HEAD(file_list);
435 FOREACH_NODE(item, file_list)
437 if (row > MAX_ITEMS_ROW)
443 text_style(bm, 0, STYLEF_MASK);
444 if (select_idx <= MAX_ITEMS_ROW)
446 if (row == select_idx && col == 0)
447 text_style(bm, STYLEF_INVERT, STYLEF_INVERT);
452 if (row == (select_idx - MAX_ITEMS_ROW) && col == NEXT_ITEM_COL)
453 text_style(bm, STYLEF_INVERT, STYLEF_INVERT);
457 text_xprintf(bm, row, col, TEXT_NORMAL, "%s", item->file_name);
461 lcd_hx8347_blitBitmap(bm);
466 static void sd_explorer(Bitmap *bm)
469 LIST_INIT(&file_list);
470 int file_list_size = 0;
473 memcpy (&item_nodes[0].file_name, "<- Return..", sizeof(item_nodes[0].file_name));
474 ADDTAIL(&file_list, &item_nodes[0].n);
476 if (SD_CARD_PRESENT())
480 bool sd_ok = sd_init(&sd, NULL, 0);
485 kprintf("Mount FAT filesystem.\n");
487 result = f_mount(0, &fs);
490 kprintf("Mounting FAT volumes error[%d]\n", result);
500 /* Open the directory */
501 result = f_opendir(&dir, "/");
504 // First element is reserved for "return" label
505 for (int i = 1;; i++)
507 /* Read a directory item */
508 result = f_readdir(&dir, &fno);
509 if (result != FR_OK || fno.fname[0] == 0)
510 break; /* Break on error or end of dir */
511 if (fno.fname[0] == '.')
512 continue; /* Ignore dot entry */
514 if (fno.fattrib & AM_DIR)
518 if (i < MAX_ITEM_NODES)
520 memcpy (&item_nodes[i].file_name, fno.fname, sizeof(item_nodes[i].file_name));
521 ADDTAIL(&file_list, &item_nodes[i].n);
526 kputs("No enought spase to show file list..\n");
539 kputs("No card insert..\n");
540 text_xprintf(bm, 5, 0, TEXT_CENTER | TEXT_FILL, "%s", "No card insert..");
544 FileItemNode *selected_node = refresh_cursor(bm, &file_list, idx);
547 keymask_t key = kbd_peek();
551 if (idx > file_list_size)
554 selected_node = refresh_cursor(bm, &file_list, idx);
555 kprintf("lidx[%d]\n", idx);
559 kprintf("ridx[%d]\n", idx);
560 wav_play(bm, selected_node->file_name);
567 static void test_draw(Bitmap *bm)
570 text_xprintf(bm, 0, 0, TEXT_NORMAL, "%s\n", "12345678.123");
571 text_xprintf(bm, 0, 10, TEXT_NORMAL, "%s\n", "12345678.123");
572 text_xprintf(bm, 1, 0, TEXT_NORMAL, "%s\n", "12345678.123");
573 text_xprintf(bm, 2, 0, TEXT_NORMAL, "%s\n", "12345678.123");
574 text_xprintf(bm, 3, 0, TEXT_NORMAL, "%s\n", "12345678.123");
575 lcd_hx8347_blitBitmap(bm);
579 if (kbd_peek() & KEY_MASK)
583 static struct MenuItem sub_items[] =
585 { (const_iptr_t)"un", 0, (MenuHook)0, NULL },
586 { (const_iptr_t)"du", 0, (MenuHook)0, NULL },
587 { (const_iptr_t)"tr", 0, (MenuHook)0, NULL },
588 { (const_iptr_t)0, 0, NULL, (iptr_t)0 }
590 static struct Menu sub_menu = { sub_items, "BeRTOS", MF_SAVESEL, &lcd_bitmap, 0, lcd_hx8347_blitBitmap };
592 static struct MenuItem main_items[] =
594 { (const_iptr_t)"Screen saver demo", 0, (MenuHook)screen_saver, &lcd_bitmap },
595 { (const_iptr_t)"Display brightness", 0, (MenuHook)setBrightness, &lcd_bitmap },
596 { (const_iptr_t)"SD dir", 0, (MenuHook)sd_explorer, (iptr_t)&lcd_bitmap },
597 { (const_iptr_t)"Reboot", 0, (MenuHook)soft_reset, &lcd_bitmap },
598 { (const_iptr_t)0, 0, NULL, (iptr_t)0 }
600 static struct Menu main_menu = { main_items, "BeRTOS", MF_STICKY | MF_SAVESEL, &lcd_bitmap, 0, lcd_hx8347_blitBitmap };
615 kprintf("sam3x %s: %d times\n", VERS_HOST, VERS_BUILD);
618 i2c_init(&i2c, I2C_BITBANG0, CONFIG_I2C_FREQ);
619 i2s_init(&i2s, SSC0);
621 wm8731_init(&wm8731_ctx, &i2c, CODEC_ADDR);
622 wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0);
624 kprintf("CPU Frequecy:%ld\n", CPU_FREQ);
627 /* Enable the adc to read internal temperature sensor */
632 lcd_setBacklight(lcd_brightness);
634 gfx_bitmapInit(&lcd_bitmap, raster, LCD_WIDTH, LCD_HEIGHT);
635 gfx_setFont(&lcd_bitmap, &font_luBS14);
636 lcd_hx8347_blitBitmap(&lcd_bitmap);
640 hp_proc = proc_new(hp_process, NULL, PROC_STACK_SIZE, hp_stack);
641 lp_proc = proc_new(lp_process, NULL, PROC_STACK_SIZE, lp_stack);
643 proc_setPri(hp_proc, 2);
644 proc_setPri(lp_proc, 1);
646 lcd_hx8347_blitBitmap24(10, 52, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, bmp_logo);
652 menu_handle(&main_menu);