X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=boards%2Fsam3x-ek%2Fexamples%2Fsam3x-ek_codec%2Fmain.c;h=2d49b12a84b8778544c46d398898bdf506e89ab9;hb=c5bc6f8c6d32f897b2b035d328d5378ec6e7711e;hp=314180a5947c3da75183460c3724c62c74632ebd;hpb=4ff8cc495329e3990c56de44975681a647c21bd5;p=bertos.git diff --git a/boards/sam3x-ek/examples/sam3x-ek_codec/main.c b/boards/sam3x-ek/examples/sam3x-ek_codec/main.c index 314180a5..2d49b12a 100644 --- a/boards/sam3x-ek/examples/sam3x-ek_codec/main.c +++ b/boards/sam3x-ek/examples/sam3x-ek_codec/main.c @@ -30,16 +30,19 @@ * * --> * - * \author Stefano Federico + * \brief Atmel SAM3X-EK testcase * - * \brief Empty project. - * - * This is a minimalist project, it just initializes the hardware of the - * supported board and proposes an empty main. + * \author Stefano Fedrigo */ +#include "bitmaps.h" + #include "hw/hw_led.h" +#include "hw/hw_lcd.h" +#include "hw/hw_adc.h" +#include "hw/hw_sdram.h" #include "hw/hw_sd.h" + #include "cfg/cfg_i2s.h" #include @@ -47,171 +50,198 @@ #include #include -#include -#include - +#include #include #include #include -#include #include #include #include #include #include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include #include +#include + +#include + #include #include +#include #include +// Keyboard +#define KEY_MASK (K_LEFT | K_RIGHT) + /* * Codec has 7-bit address, the eighth is the R/W bit, so we * write the codec address with one bit shifted left */ #define CODEC_ADDR 0x36 +// Kernel +static PROC_DEFINE_STACK(play_proc_stack, 1024); +static PROC_DEFINE_STACK(rec_proc_stack, 1024); +MsgPort proc_play_inPort; +MsgPort proc_rec_inPort; +#define MAX_ITEM_NODES 30 +#define MAX_ITEMS_ROW 15 +#define NEXT_ITEM_COL 10 -typedef struct WavHdr +typedef struct FileItemNode { - char chunk_id[4]; - uint32_t chunk_size; - char format[4]; - - char subchunk1_id[4]; - uint32_t subchunk1_size; - uint16_t audio_format; - uint16_t num_channels; - uint32_t sample_rate; - uint32_t byte_rate; - uint16_t block_align; - uint16_t bits_per_sample; - - uint8_t subchunk2[8]; -} WavHdr; + Node n; + char file_name[13]; +} FileItemNode; +typedef struct AudioMsg +{ + Msg msg; + char file_name[13]; +} AudioMsg; -//#define FILE_NAME "input0.wav" -//#define FILE_NAME "due.wav" -//#define FILE_NAME "sample.wav" -//#define FILE_NAME "testaa" -#define FILE_NAME "outfile.wav" -#define ACQ_FILE_NAME "acq.wav" +FileItemNode item_nodes[MAX_ITEM_NODES]; -uint8_t tmp[4096]; +uint8_t tmp[10240]; // SD fat filesystem context FATFS fs; -FatFile log_file; -FatFile acq_file; +FatFile play_file; +FatFile rec_file; +static Sd sd; static I2c i2c; static I2s i2s; static Wm8731 wm8731_ctx; -static void init(void) -{ - IRQ_ENABLE; - kdbg_init(); - kprintf("sam3x %s: %d times\n", VERS_HOST, VERS_BUILD); - - timer_init(); - LED_INIT(); - - adc_init(); - dmac_init(); - i2c_init(&i2c, I2C_BITBANG0, CONFIG_I2C_FREQ); - i2s_init(&i2s, SSC0); - - wm8731_init(&wm8731_ctx, &i2c, CODEC_ADDR); - wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0); -} - -size_t count = 0; - -static void codec(struct I2s *i2s, void *_buf, size_t len) +static uint8_t raster[RAST_SIZE(LCD_WIDTH, LCD_HEIGHT)]; +static Bitmap lcd_bitmap; +extern Font font_gohu; +static int lcd_brightness = LCD_BACKLIGHT_MAX; +static uint16_t headphone_volume = 90; +static size_t played_size = 0; +static size_t recorded_size = 0; +static bool is_playing = false; +static bool is_recording = false; +static int recorderd_file_idx; + +static void codec_play(struct I2s *i2s, void *_buf, size_t len) { - count += kfile_read(&log_file.fd, _buf, len); - if (count >= log_file.fat_file.fsize - sizeof(WavHdr)) + played_size += kfile_read(&play_file.fd, _buf, len); + if (played_size >= play_file.fat_file.fsize - sizeof(WavHdr)) { - kprintf("stop %d\n", count); + kprintf("stop %d\n", played_size); i2s_dmaTxStop(i2s); - count = 0; + is_playing = false; + played_size = 0; } } -static int wav_check(KFile *fd) +static void codec_rec(struct I2s *i2s, void *buf, size_t len) { + (void)i2s; + ASSERT(buf); + ASSERT(len != 0); + ASSERT(&rec_file.fd); - WavHdr header; + recorded_size += kfile_write(&rec_file.fd, buf, len); +} - if (kfile_read(fd, &header, sizeof(header)) != sizeof(header)) +static void NORETURN play_proc(void) +{ + while (1) { - kputs("Error reading wave file header\n"); - return EOF; - } + event_wait(&proc_play_inPort.event); + AudioMsg *play; + play = (AudioMsg *)msg_get(&proc_play_inPort); + if (play && SD_CARD_PRESENT()) + { + timer_delay(10); - if (strncmp(header.chunk_id, "RIFF", 4)) - { - kputs("RIFF tag not found\n"); - goto error; - } + bool sd_ok = sd_init(&sd, NULL, 0); + FRESULT result; - if (strncmp(header.format, "WAVE", 4)) - { - kputs("WAVE tag not found\n"); - goto error; - } + if (sd_ok) + { + kprintf("Mount FAT filesystem.\n"); - if (le16_to_cpu(header.audio_format) != 1) - { - kprintf("Audio format not valid, found [%d]\n", le16_to_cpu(header.audio_format)); - goto error; - } + result = f_mount(0, &fs); + if (result != FR_OK) + { + kprintf("Mounting FAT volumes error[%d]\n", result); + sd_ok = false; + } - if (le16_to_cpu(header.num_channels) != 2) - { - kprintf("Channels number not valid, found [%d]\n", le16_to_cpu(header.num_channels)); - goto error; - } + if (sd_ok) + { + result = fatfile_open(&play_file, play->file_name, FA_OPEN_EXISTING | FA_READ); + if (result == FR_OK) + { + kprintf("Open file: %s size %ld\n", play->file_name, play_file.fat_file.fsize); + WavHdr wav; + kfile_read(&play_file.fd, &wav, sizeof(WavHdr)); + if (wav_checkHdr(&wav, 1, CONFIG_CHANNEL_NUM, CONFIG_SAMPLE_FREQ, CONFIG_WORD_BIT_SIZE) != -1) + { + kputs("Wav file play..\n"); + wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, headphone_volume); + is_playing = true; + i2s_dmaStartTxStreaming(&i2s, tmp, sizeof(tmp), sizeof(tmp) / 2, codec_play); - if (le32_to_cpu(header.sample_rate) != 44100) - { - kprintf("Sample rate not valid, found [%ld]\n", le32_to_cpu(header.sample_rate)); - goto error; - } + wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0); + } - if (le16_to_cpu(header.bits_per_sample) != 16) - { - kprintf("Bits per sample not valid, found [%d]\n", le16_to_cpu(header.bits_per_sample)); - goto error; + // Flush data and close the files. + kfile_flush(&play_file.fd); + kfile_close(&play_file.fd); + } + else + { + kprintf("Unable to open file: '%s' error[%d]\n", play->file_name, result); + } + } + f_mount(0, NULL); + } + } } - return 0; - -error: - return 1; } -int main(void) -{ - init(); - for (;;) +static void NORETURN rec_proc(void) +{ + while (1) { - if (SD_CARD_PRESENT()) + event_wait(&proc_rec_inPort.event); + AudioMsg *rec; + rec = (AudioMsg *)msg_get(&proc_rec_inPort); + if (rec && SD_CARD_PRESENT()) { timer_delay(10); - Sd sd; + bool sd_ok = sd_init(&sd, NULL, 0); FRESULT result; if (sd_ok) { kprintf("Mount FAT filesystem.\n"); + result = f_mount(0, &fs); if (result != FR_OK) { @@ -221,50 +251,394 @@ int main(void) if (sd_ok) { - result = fatfile_open(&log_file, FILE_NAME, FA_OPEN_EXISTING | FA_READ); + result = fatfile_open(&rec_file, rec->file_name, FA_CREATE_ALWAYS | FA_WRITE); if (result == FR_OK) { - kprintf("Opened log file '%s' size %ld\n", FILE_NAME, log_file.fat_file.fsize); - wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, adc_read(1)); - if (wav_check(&log_file.fd) >= 0) - { - kputs("Wav file play..\n"); - i2s_dmaStartTxStreaming(&i2s, tmp, sizeof(tmp), sizeof(tmp) / 4, codec); - } + kprintf("Open file: %s size %ld\n", rec->file_name, rec_file.fat_file.fsize); + kputs("Rec Wav file..\n"); + is_recording = true; + // Leave place for wav header + kfile_seek(&rec_file.fd, sizeof(WavHdr), KSM_SEEK_SET); + + i2s_dmaStartRxStreaming(&i2s, tmp, sizeof(tmp), sizeof(tmp) / 2, codec_rec); - wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0); + // write header + WavHdr wav; + wav_writeHdr(&wav, recorded_size, 1, CONFIG_CHANNEL_NUM, CONFIG_SAMPLE_FREQ, CONFIG_WORD_BIT_SIZE); + kfile_seek(&rec_file.fd, 0, KSM_SEEK_SET); + kfile_write(&rec_file.fd, &wav, sizeof(WavHdr)); // Flush data and close the files. - kfile_flush(&log_file.fd); - kfile_close(&log_file.fd); + kfile_flush(&rec_file.fd); + kfile_close(&rec_file.fd); } else { - kprintf("Unable to open file: '%s' error[%d]\n", FILE_NAME, result); + kprintf("Unable to open file: '%s' error[%d]\n", rec->file_name, result); } - - //Unmount always to prevent accidental sd remove. - f_mount(0, NULL); - kprintf("Umount\n"); - } f_mount(0, NULL); } + } + } +} + + +INLINE void start_play(char *file_name) +{ + played_size = 0; + + AudioMsg play_msg; + memcpy(play_msg.file_name, file_name, sizeof(play_msg.file_name)); + msg_put(&proc_play_inPort, &play_msg.msg); +} + +INLINE void stop_play(void) +{ + i2s_dmaTxStop(&i2s); + is_playing = false; +} + + +INLINE void start_rec(char *file_name) +{ + recorded_size = 0; + + AudioMsg rec_msg; + memcpy(rec_msg.file_name, file_name, sizeof(rec_msg.file_name)); + msg_put(&proc_rec_inPort, &rec_msg.msg); +} + +INLINE void stop_rec(void) +{ + i2s_dmaRxStop(&i2s); + is_recording = false; +} + +INLINE FileItemNode *select_item(Bitmap *bm, List *file_list, int select_idx) +{ + FileItemNode *item; + FileItemNode *select_node; + int col = 0; + int row = 0; + + gfx_bitmapClear(bm); + select_node = (FileItemNode *)LIST_HEAD(file_list); + FOREACH_NODE(item, file_list) + { + if (row > MAX_ITEMS_ROW) + { + row = 1; + col = NEXT_ITEM_COL; + } - timer_delay(5000); + text_style(bm, 0, STYLEF_MASK); + if (select_idx <= MAX_ITEMS_ROW) + { + if (row == select_idx && col == 0) + { + text_style(bm, STYLEF_INVERT, STYLEF_INVERT); + select_node = item; + } } else { - kputs("No card insert..\n"); - timer_delay(500); + if (row == (select_idx - MAX_ITEMS_ROW) && col == NEXT_ITEM_COL) + { + text_style(bm, STYLEF_INVERT, STYLEF_INVERT); + select_node = item; + } + } + + text_xprintf(bm, row, col, TEXT_NORMAL, "%s", item->file_name); + row++; + } + + lcd_hx8347_blitBitmap(bm); + + return select_node; +} + +static void play_menu(Bitmap *bm) +{ + List file_list; + LIST_INIT(&file_list); + int file_list_size = 0; + gfx_bitmapClear(bm); + + memcpy (&item_nodes[0].file_name, "<- Return..", sizeof(item_nodes[0].file_name)); + ADDTAIL(&file_list, &item_nodes[0].n); + + if (SD_CARD_PRESENT()) + { + timer_delay(10); + + bool sd_ok = sd_init(&sd, NULL, 0); + FRESULT result; + + if (sd_ok) + { + kprintf("Mount FAT filesystem.\n"); + result = f_mount(0, &fs); + if (result != FR_OK) + { + kprintf("Mounting FAT volumes error[%d]\n", result); + sd_ok = false; + } + + if (sd_ok) + { + FILINFO fno; + DIR dir; + + kputs("open dir\n"); + /* Open the directory */ + result = f_opendir(&dir, "/"); + if (result == FR_OK) + { + // First element is reserved for "return" label + for (int i = 1;; i++) + { + /* Read a directory item */ + result = f_readdir(&dir, &fno); + if (result != FR_OK || fno.fname[0] == 0) + break; /* Break on error or end of dir */ + if (fno.fname[0] == '.') + continue; /* Ignore dot entry */ + if (fno.fattrib & AM_DIR) + continue; + else + { + if (i < MAX_ITEM_NODES) + { + memcpy (&item_nodes[i].file_name, fno.fname, sizeof(item_nodes[i].file_name)); + ADDTAIL(&file_list, &item_nodes[i].n); + file_list_size++; + kprintf("%s\n", item_nodes[i].file_name); + } + else + { + kputs("No enought space to store items in list\n"); + break; + } + } + } + } + } + f_mount(0, NULL); + kprintf("Umount\n"); } } + else + { + kputs("No card insert..\n"); + text_xprintf(bm, 5, 0, TEXT_CENTER | TEXT_FILL, "%s", "No card insert.."); + } + + int idx = 0; + FileItemNode *selected_node = NULL; + select_item(bm, &file_list, idx); + while (1) + { + keymask_t key = kbd_peek(); + if ((key & K_LEFT) && !is_playing) + { + idx++; + if (idx > file_list_size) + idx = 0; - return 0; + selected_node = select_item(bm, &file_list, idx); + } + if (key & K_RIGHT) + { + if (idx == 0) + break; + + if (!is_playing) + start_play(selected_node->file_name); + else + stop_play(); + } + + cpu_relax(); + } } +static void rec_menu(Bitmap *bm) +{ + gfx_bitmapClear(bm); + text_style(bm, STYLEF_BOLD | STYLEF_UNDERLINE, STYLEF_BOLD | STYLEF_UNDERLINE); + text_xprintf(bm, 0, 0, TEXT_CENTER | TEXT_FILL, "Microphone recorder."); + text_style(bm, 0, STYLEF_MASK); + text_xprintf(bm, 2, 0, TEXT_NORMAL, "Press RIGHT button to start recording"); + text_xprintf(bm, 3, 0, TEXT_NORMAL, "and to stop it re-press RIGHT button."); + lcd_hx8347_blitBitmap(bm); + + ticks_t start= 0; + while (1) + { + keymask_t key = kbd_peek(); + if ((key & K_LEFT) && (!is_recording)) + { + break; + } + if (key & K_RIGHT) + { + char file_name[13]; + memset(file_name, 0, sizeof(file_name)); + sprintf(file_name, "REC%d.WAV", recorderd_file_idx); + kprintf("rec %s\n", file_name); + + if (!is_recording) + { + start_rec(file_name); + text_xprintf(bm, 5, 0, TEXT_CENTER | TEXT_FILL, "Start recording on file: %s", file_name); + text_xprintf(bm, 6, 0, TEXT_CENTER | TEXT_FILL, " "); + lcd_hx8347_blitBitmap(bm); + start = timer_clock(); + } + else + { + stop_rec(); + recorderd_file_idx++; + text_xprintf(bm, 5, 0, TEXT_CENTER | TEXT_FILL, "Stop recording: %s", file_name); + mtime_t elaps = ticks_to_ms(timer_clock() - start); + text_xprintf(bm, 6, 0, TEXT_CENTER | TEXT_FILL, "Recorded: %ld.%ldsec", elaps / 1000, elaps % 1000); + lcd_hx8347_blitBitmap(bm); + } + } + cpu_relax(); + } +} +/* + * Lcd + */ +static void setBrightness(Bitmap *bm) +{ + while (1) + { + gfx_bitmapClear(bm); + text_xprintf(bm, 1, 0, TEXT_FILL | TEXT_CENTER, "Brightness: %d", lcd_brightness); + text_xprintf(bm, 3, 0, TEXT_FILL | TEXT_CENTER, "RIGHT key: change"); + text_xprintf(bm, 4, 0, TEXT_FILL | TEXT_CENTER, "LEFT key: back "); + lcd_hx8347_blitBitmap(bm); + + keymask_t mask = kbd_get(); + + if (mask & K_LEFT) + break; + else if (mask & K_RIGHT) + { + if (++lcd_brightness > LCD_BACKLIGHT_MAX) + lcd_brightness = 0; + lcd_setBacklight(lcd_brightness); + } + } +} + +static void setVolume(Bitmap *bm) +{ + gfx_bitmapClear(bm); + text_style(bm, STYLEF_BOLD | STYLEF_UNDERLINE, STYLEF_BOLD | STYLEF_UNDERLINE); + text_xprintf(bm, 0, 0, TEXT_CENTER, "Headphone Volume"); + text_style(bm, 0, STYLEF_MASK); + text_xprintf(bm, 2, 0, TEXT_NORMAL, "Turn VR1 potentiometer to adjust it."); + + while (1) + { + headphone_volume = ADC_RANGECONV(adc_read(1), 0, 100); + text_xprintf(bm, 5, 0, TEXT_FILL | TEXT_CENTER, "Volume %d%%", headphone_volume); + lcd_hx8347_blitBitmap(bm); + + timer_delay(400); + if (kbd_peek() & KEY_MASK) + break; + } +} + +static void NORETURN soft_reset(Bitmap * bm) +{ + int i; + + gfx_bitmapClear(bm); + for (i = 5; i; --i) + { + text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "%d", i); + lcd_hx8347_blitBitmap(bm); + timer_delay(1000); + } + text_xprintf(bm, 2, 0, TEXT_FILL | TEXT_CENTER, "REBOOT"); + lcd_hx8347_blitBitmap(bm); + timer_delay(1000); + + /* Perform a software reset request */ + HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ; + UNREACHABLE(); +} + + +static struct MenuItem main_items[] = +{ + { (const_iptr_t)"Play SD file", 0, (MenuHook)play_menu, (iptr_t)&lcd_bitmap }, + { (const_iptr_t)"Record file on SD", 0, (MenuHook)rec_menu, (iptr_t)&lcd_bitmap }, + { (const_iptr_t)"Set brightness", 0, (MenuHook)setBrightness, (iptr_t)&lcd_bitmap }, + { (const_iptr_t)"Set volume", 0, (MenuHook)setVolume, (iptr_t)&lcd_bitmap }, + { (const_iptr_t)"Reboot", 0, (MenuHook)soft_reset, (iptr_t)&lcd_bitmap }, + { (const_iptr_t)0, 0, NULL, (iptr_t)0 } +}; +static struct Menu main_menu = { main_items, "BeRTOS", MF_STICKY | MF_SAVESEL, &lcd_bitmap, 0, lcd_hx8347_blitBitmap }; + + +int main(void) +{ + IRQ_ENABLE; + kdbg_init(); + + LED_INIT(); + timer_init(); + + proc_init(); + sdram_init(); + adc_init(); + + kprintf("sam3x %s: %d times\n", VERS_HOST, VERS_BUILD); + + dmac_init(); + i2c_init(&i2c, I2C_BITBANG0, CONFIG_I2C_FREQ); + i2s_init(&i2s, SSC0); + + wm8731_init(&wm8731_ctx, &i2c, CODEC_ADDR); + wm8731_setVolume(&wm8731_ctx, WM8731_HEADPHONE, 0); + + kprintf("CPU Frequecy:%ld\n", CPU_FREQ); + + lcd_hx8347_init(); + lcd_setBacklight(lcd_brightness); + + gfx_bitmapInit(&lcd_bitmap, raster, LCD_WIDTH, LCD_HEIGHT); + gfx_setFont(&lcd_bitmap, &font_luBS14); + lcd_hx8347_blitBitmap(&lcd_bitmap); + + kbd_init(); + + proc_new(play_proc, NULL, sizeof(play_proc_stack), play_proc_stack); + proc_new(rec_proc, NULL, sizeof(rec_proc_stack), rec_proc_stack); + msg_initPort(&proc_play_inPort, event_createGeneric()); + msg_initPort(&proc_rec_inPort, event_createGeneric()); + + lcd_hx8347_blitBitmap24(10, 52, BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, bmp_logo); + timer_delay(500); + + + while (1) + { + menu_handle(&main_menu); + cpu_relax(); + } + +}