The "GR-PEACH_Audio_Playback_7InchLCD_Sample" is a sample code that can provides high-resolution audio playback of FLAC format files. It also allows the user to audio-playback control functions such as play, pause, and stop by manipulating key switches.

Dependencies:   GR-PEACH_video R_BSP TLV320_RBSP USBHost_custom

Fork of GR-PEACH_Audio_Playback_Sample by Renesas

Note

For a sample program of without LCD Board, please refer to GR-PEACH_Audio_Playback_Sample.

Introduction

The "GR-PEACH_Audio_Playback_7InchLCD_Sample" is a sample code that can provides high-resolution audio playback of FLAC format files. It also allows the user to audio-playback control functions such as play, pause, and stop by manipulating key switches.

1. Overview of the Sample Code

1.1 Software Block Diagram

Figure 1.1 shows the software block diagram.

/media/uploads/1050186/lcd_figure1_1.png

1.2 Pin Definitions

Table 1.1 shows the pins used in this sample code.

/media/uploads/1050186/lcd_table1_1.png

2. Sample Code Operating Environment

In order to operate this sample code, GR-PEACH, Audio Camera Shield and 7.1 inch LCD Shield must be needed. For details on Audio Camera Shield and 7.1 inch LCD Shield, please refer to the following links, respectively:

In this section, it is described that how board is configured and to control audio playback via command line and touch screen.

2.1 Operating Environment

Figure 2.1 shows the overview of the operating environment for this sample code.

/media/uploads/1050186/lcd_figure2_1.png

Figure 2.2 and 2.3 show how to configure GR-PEACH, Audio Camera Shield and 7.1 inch LCD shield when using USB0 and USB1, respectively.

/media/uploads/1050186/lcd_figure2_2.png /media/uploads/1050186/lcd_figure2_3.png

Table 2.1 lists the overview of Graphical User Interface (GUI) of this sample code.

/media/uploads/1050186/lcd_table2_1.png

2.2 List of User Operations

Table 2.2 shows the relationship among Audio Playback, Command Line and Onboard Switch.

/media/uploads/1050186/lcd_table2_2.png

3. Function Outline

Table 3.1, 3.2 and 3.3 shows the overview of functions implemented in this sample code.

/media/uploads/1050186/lcd_table3_1.png /media/uploads/1050186/lcd_table3_2.png /media/uploads/1050186/lcd_table3_3.png /media/uploads/1050186/lcd_figure3_1.png

3.1 Playback Control

This sample program supports the operation "play", "pause", "stop", "play next song" and "play previous song".

3.2 Trick Play Control

In order to enable/disable Repeat Mode, user need to type "repeat" on command line or click the corresponding icon shown in Table 2.2. By derault, Repeat Mode is enabled. When Repeat Mode is enabled, the first song is played back after the playback of the last song is finished. Otherwise, the playback is shopped when finishing to play back the last song.

3.3 How to see Song Information

The information of the song being played back can be seen by typing playinfo on command line. Table 3.4 lists the items user can see on the terminal.

/media/uploads/dkato/audioplayback_table3_4.png

3.4 How to analyze the folder structure in USB stick

In this sample code, the folder structure in USB stick is analyzed in the breadth-first order. Table 3.5 shows how the files in USB stick are numbered.

/media/uploads/dkato/audioplayback_table3_5.png

4.Others

4.1 Serial Communication Setting

With respect to the default serial communication related setting on mbed, please refer to the follwing link:
https://developer.mbed.org/teams/Renesas/wiki/GR-PEACH-Getting-Started#install-the-usb-serial-communication
Please set up the terminal software you would like to use on your PC in consideration of the above. For example, 9600 should be specified for the baud rate on the terminal in order to control this sample via command line.

4.2 Necessary modification when using GCC ARM Embedded

If you would like to use GCC ARM Embedded, you must revise the following linker script incorporated in mbed OS 5 package as follows:

  • Linker Script to be modified
    $(PROJECT_ROOT)/mbed-os/targets/TARGET_RENESAS/TARGET_RZ_A1H/device/TOOLCHAIN_GCC_ARM/RZA1H.ld

    Please note that $(PROJECT_ROOT) in the above denotes the root directory of this sample code

  • Before Modification

RZA1H.ld

/* Linker script for mbed RZ_A1H */

/* Linker script to configure memory regions. */
MEMORY
{
  ROM   (rx)  : ORIGIN = 0x00000000, LENGTH = 0x02000000
  BOOT_LOADER (rx) : ORIGIN = 0x18000000, LENGTH = 0x00004000 
  SFLASH (rx) : ORIGIN = 0x18004000, LENGTH = 0x07FFC000 
  L_TTB (rw)  : ORIGIN = 0x20000000, LENGTH = 0x00004000 
  RAM (rwx) : ORIGIN = 0x20020000, LENGTH = 0x00700000
  RAM_NC (rwx) : ORIGIN = 0x20900000, LENGTH = 0x00100000
}
(snip)
  • After Modification

RZA1H.ld

/* Linker script for mbed RZ_A1H */

/* Linker script to configure memory regions. */
MEMORY
{
  ROM   (rx)  : ORIGIN = 0x00000000, LENGTH = 0x02000000
  BOOT_LOADER (rx) : ORIGIN = 0x18000000, LENGTH = 0x00004000 
  SFLASH (rx) : ORIGIN = 0x18004000, LENGTH = 0x07FFC000 
  L_TTB (rw)  : ORIGIN = 0x20000000, LENGTH = 0x00004000 
  RAM (rwx) : ORIGIN = 0x20020000, LENGTH = 0x00180000
  RAM_NC (rwx) : ORIGIN = 0x20200000, LENGTH = 0x00680000
}
(snip)

display/disp_tft.cpp

Committer:
Osamu Nakamura
Date:
2017-04-11
Revision:
6:a957aaa284f0
Parent:
4:2672de88a46b

File content as of revision 6:a957aaa284f0:

/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer*
* Copyright (C) 2015 Renesas Electronics Corporation. All rights reserved.
*******************************************************************************/

#include "mbed.h"
#include "rtos.h"
#include "misratypes.h"
#include "DisplayBace.h"
#include "display.h"
#include "disp_tft.h"
#include "disp_tft_scrn.h"

/*--- Macro definition of LCD display driver ---*/
#define LCD_INPUT_CLK           (66.67)     /* Input clock: P1 clk [MHz] */
#define LCD_OUTPUT_CLK          (33.26)     /* Output clock: LCD clk [MHz] */
#define LCD_HSYNC_PERIOD        (1056)      /* Free-running Hsync period: 800 + 92 + 128 + 36 */
#define LCD_VSYNC_PERIOD        (525)       /* Free-running Vsync period: 480 + 5 + 35 + 5 */
#define LCD_H_BACK_PORCH        (164)       /* LCD display horizontal back porch period: 128 + 36 */
#define LCD_V_BACK_PORCH        (40)        /* LCD display vertical back porch period: 35 + 5 */
#define LCD_PIN_NUM             (8)
#define LCD_INPUT_FORMAT_SIZE   (4u)

/* Power ON sequence */
#define BLON_WAIT_TIME_MS       (200)       /* Wait time of milisecond before the backlight ON. */

/* Frame buffer stride: Frame buffer stride should be set to a multiple of 32 or 128 */
/* in accordance with the frame buffer burst transfer mode. */
#define BUF_STRIDE              (((DSP_TFT_WIDTH * LCD_INPUT_FORMAT_SIZE) + 31u) & ~31u)
#define BUF_HEIGHT              (DSP_TFT_HEIGHT)
#define BUF_SIZE                (BUF_STRIDE * BUF_HEIGHT)

#if defined( __CC_ARM )
#define VRAM_SECTION1           __attribute((at(0x60100000)))
#define VRAM_SECTION2           __attribute((at(0x60480000)))
#define VRAM_SECTION3           __attribute((at(0x60600000)))
#define VRAM_SECTION4           __attribute((at(0x60780000)))
#else  /* !defined( __CC_ARM ) */
/* CAUTION! */
/* Modify the start address of "NC_BSS" section in "RZA1H.ld" file. */
#define VRAM_SECTION            __attribute((section("NC_BSS"),aligned(16)))
#define VRAM_SECTION1           VRAM_SECTION
#define VRAM_SECTION2           VRAM_SECTION
#define VRAM_SECTION3           VRAM_SECTION
#define VRAM_SECTION4           VRAM_SECTION
#endif /* defined( __CC_ARM ) */

#define SHIFT_1BIT_SIZE         (1u)

static void init_lcd_driver(const dsp_tft_ctrl_t * const p_tft);
static void update_tft_display(dsp_tft_ctrl_t * const p_tft, const uint32_t layer_id);
static void update_tft_audio_data(const dsp_com_ctrl_t * const p_com, dsp_tft_ctrl_t * const p_tft);
static void vsync_callback(DisplayBase::int_type_t int_type);
static DisplayBase::graphics_layer_t convert_layer_id(const uint32_t layer_id);
static void swap_frame_buffer(dsp_tftlayer_t * const p_info);

static DisplayBase lcd;

void dsp_init_tft(dsp_tft_ctrl_t * const p_tft)
{
    static uint32_t VRAM_SECTION1   frame_buffer_1[BUF_SIZE/sizeof(uint32_t)];
    static uint32_t VRAM_SECTION2   frame_buffer_2[BUF_SIZE/sizeof(uint32_t)];
    static uint32_t VRAM_SECTION3   frame_buffer_3[BUF_SIZE/sizeof(uint32_t)];
    static uint32_t VRAM_SECTION4   frame_buffer_4[BUF_SIZE/sizeof(uint32_t)];
    uint32_t                        i;

    if (p_tft != NULL) {
        p_tft->key_code = SYS_KEYCODE_NON;
        (void) memset(frame_buffer_1, 0, sizeof(frame_buffer_1));
        (void) memset(frame_buffer_2, 0, sizeof(frame_buffer_2));
        (void) memset(frame_buffer_3, 0, sizeof(frame_buffer_3));
        (void) memset(frame_buffer_4, 0, sizeof(frame_buffer_4));
        p_tft->tft_info[DSP_TFT_LAYER_0].p_disp_buf = &frame_buffer_1[0];
        p_tft->tft_info[DSP_TFT_LAYER_0].p_back_buf = &frame_buffer_2[0];
        p_tft->tft_info[DSP_TFT_LAYER_1].p_disp_buf = &frame_buffer_3[0];
        p_tft->tft_info[DSP_TFT_LAYER_1].p_back_buf = &frame_buffer_4[0];
        for (i = 0u; i < DSP_TFT_LAYER_NUM; i++) {
            p_tft->tft_info[i].width  = DSP_TFT_WIDTH;
            p_tft->tft_info[i].height = DSP_TFT_HEIGHT;
            p_tft->tft_info[i].stride = BUF_STRIDE;
        }
        init_lcd_driver(p_tft);
        dsp_init_tft_scrn(p_tft);
    }
}

void dsp_output_tft(const DSP_MAIL_ID mail_id, 
                    const dsp_com_ctrl_t * const p_com, dsp_tft_ctrl_t * const p_tft)
{
    uint32_t                        result = DSP_TFT_LAYER_NON;

    if ((p_com != NULL) && (p_tft != NULL)) {
        switch (mail_id) {
            case DSP_MAILID_CYCLE_IND :
                /* Executes main function of the playback screen. */
                result = dsp_make_tft_scrn(p_com, p_tft);
                break;
            case DSP_MAILID_PLAY_TIME :
            case DSP_MAILID_PLAY_INFO :
            case DSP_MAILID_PLAY_STAT :
                if (p_com->edge_track_change == true) {
                    dsp_clear_tft_audio_data(p_tft);
                }
                result = DSP_TFT_LAYER_NON;
                break;
            case DSP_MAILID_AUDIO_FIN:
                update_tft_audio_data(p_com, p_tft);
                result = DSP_TFT_LAYER_NON;
                break;
            case DSP_MAILID_CMD_STR :
            case DSP_MAILID_PRINT_STR :
            case DSP_MAILID_FILE_NAME :
            default :
                result = DSP_TFT_LAYER_NON;
                break;
        }
        if (result < DSP_TFT_LAYER_NUM) {
            /* Updates the TFT display. */
            update_tft_display(p_tft, result);
        }
    }
}

SYS_KeyCode dsp_convert_key_tft(const uint32_t disp_mode, const uint32_t pos_x, const uint32_t pos_y)
{
    SYS_KeyCode     ret;

    switch (disp_mode) {
        case DSP_DISPMODE_1:
        case DSP_DISPMODE_2:
        case DSP_DISPMODE_3:
            ret = dsp_convert_key_tft_scrn(pos_x, pos_y);
            break;
        default:
            ret = SYS_KEYCODE_NON;
            break;
    }
    return ret;
}

void dsp_clear_tft_audio_data(dsp_tft_ctrl_t * const p_tft)
{
    dsp_audio_t     *p_aud;

    if (p_tft != NULL) {
        p_aud = &p_tft->audio_data;
        p_aud->m2_buf_cnt = 0u;
        (void) memset(&p_aud->m2_buf[0], 0u, sizeof(p_aud->m2_buf));
        p_aud->m3_buf_cnt = 0u;
        (void) memset(&p_aud->m3_buf[0], 0u, sizeof(p_aud->m3_buf));
        p_aud->m3_sample_cnt = 0u;
        p_aud->m3_target_cnt = 0u;
        p_aud->m3_pause_flag = false;
    }
}

/** Initializes LCD driver using DisplayBase class.
 *
 *  @param p_tft Pointer to management data of TFT module.
 */
static void init_lcd_driver(const dsp_tft_ctrl_t * const p_tft)
{
    DisplayBase::graphics_error_t   grap_err;
    DisplayBase::rect_t             rect;
    DisplayBase::lcd_config_t       lcd_config = {
        DisplayBase::LCD_TYPE_LVDS,         /* LVDS or Pararel RGB */
        LCD_INPUT_CLK,                      /* P1  clk [MHz] */
        LCD_OUTPUT_CLK,                     /* LCD clk [MHz] */

        DisplayBase::LCD_OUTFORMAT_RGB888,  /* Output format select */
        DisplayBase::EDGE_RISING,           /* Output phase control of LCD_DATA23 to LCD_DATA0 pin */

        LCD_HSYNC_PERIOD,                   /* Free-running Hsync period */
        LCD_VSYNC_PERIOD,                   /* Free-running Vsync period */
        (uint16_t)DSP_TFT_WIDTH,            /* LCD display area size, horizontal width */
        (uint16_t)DSP_TFT_HEIGHT,           /* LCD display area size, vertical width */
        LCD_H_BACK_PORCH,                   /* LCD display horizontal back porch period */
        LCD_V_BACK_PORCH,                   /* LCD display vertical back porch period */

        DisplayBase::LCD_TCON_PIN_NON,      /* TCONn or Not use(-1) */
        DisplayBase::SIG_POL_NOT_INVERTED,  /* Polarity inversion control of signal */
        0,                                  /* Hsync width */

        DisplayBase::LCD_TCON_PIN_NON,      /* TCONn or Not use(-1) */
        DisplayBase::SIG_POL_NOT_INVERTED,  /* Polarity inversion control of signal */
        0,                                  /* Vsync width  */

        DisplayBase::LCD_TCON_PIN_3,        /* TCONn or Not use(-1) */
        DisplayBase::SIG_POL_NOT_INVERTED   /* Polarity inversion control of signal */
    };
    PinName                         lvds_pin[LCD_PIN_NUM] = {
        P5_7, P5_6, P5_5, P5_4, P5_3, P5_2, P5_1, P5_0  /* Data pin */
    };
    static DigitalOut               lcd_pwon(P7_15);
    static DigitalOut               lcd_blon(P8_1);
    static PwmOut                   lcd_cntrst(P8_15);
    uint32_t                        i;
    DisplayBase::graphics_layer_t   layer_id;

    if (p_tft != NULL) {
        lcd_pwon.write(1);                  /* LCD panel power ON. */
        /* Graphics initialization process */
        grap_err = lcd.Graphics_init(&lcd_config);
        if (grap_err == DisplayBase::GRAPHICS_OK) {
            /* Interrupt callback function setting (Vsync signal output from scaler 0) */
            grap_err = lcd.Graphics_Irq_Handler_Set(DisplayBase::INT_TYPE_S0_LO_VSYNC, 0, &vsync_callback);
            if (grap_err == DisplayBase::GRAPHICS_OK) {
                lcd.Graphics_Lvds_Port_Init(lvds_pin, LCD_PIN_NUM);
                rect.vs = 0;
                rect.vw = (uint16_t)DSP_TFT_HEIGHT;
                rect.hs = 0;
                rect.hw = (uint16_t)DSP_TFT_WIDTH;
                for (i = 0u; i < DSP_TFT_LAYER_NUM; i++) {
                    layer_id = convert_layer_id(i);
                    lcd.Graphics_Read_Setting(layer_id, (void *)p_tft->tft_info[i].p_disp_buf, 
                                            BUF_STRIDE, DisplayBase::GRAPHICS_FORMAT_ARGB8888, 
                                            DisplayBase::WR_RD_WRSWA_32BIT, &rect);
                    lcd.Graphics_Start(layer_id);
                }

                Thread::wait(BLON_WAIT_TIME_MS);
                lcd_blon.write(1);          /* LCD panel backlight ON. */
                lcd_cntrst.write(1.0);
            }
        }
    }
}

/** Interrupt callback function for Vsync interruption.
 *
 *  @param int_type The number of VDC5 interrupt types
 */
static void vsync_callback(DisplayBase::int_type_t int_type)
{
    UNUSED_ARG(int_type);
    (void) dsp_notify_cycle_time();
}

/** Updates the display of the specified layer.
 *
 *  @param p_tft Pointer to management data of TFT module.
 *  @param layer_id The number of the display layer of TFT module.
 */
static void update_tft_display(dsp_tft_ctrl_t * const p_tft, const uint32_t layer_id)
{
    DisplayBase::graphics_layer_t   result;
    DisplayBase::graphics_error_t   grap_err;

    if ((p_tft != NULL) && (layer_id < DSP_TFT_LAYER_NUM)) {
        result = convert_layer_id(layer_id);
        grap_err = lcd.Graphics_Read_Change(result, p_tft->tft_info[layer_id].p_back_buf);
        if (grap_err == DisplayBase::GRAPHICS_OK) {
            swap_frame_buffer(&p_tft->tft_info[layer_id]);
        }
    }
}

/** Updates the audio data.
 *
 *  @param p_com Pointer to common data in all display module.
 *  @param p_tft Pointer to management data of TFT module.
 */
static void update_tft_audio_data(const dsp_com_ctrl_t * const p_com, dsp_tft_ctrl_t * const p_tft)
{
    dsp_audio_t     *p_aud;
    uint32_t        i;
    uint32_t        buf_id;
    int32_t         total_val;
    bool            update_flag;
    int16_t         new_data[DSP_TFT_M3_AUDIO_SAMPLE_PER_100MS];
    uint32_t        valid_data;

    if ((p_com != NULL) && (p_tft != NULL)) {
        p_aud = &p_tft->audio_data;
        /* Stores the display data using the display mode 2. */
        (void) memcpy(&p_aud->m2_buf[0], &p_aud->req_buf[0], sizeof(p_aud->m2_buf));
        p_aud->m2_buf_cnt = sizeof(p_aud->m2_buf)/sizeof(p_aud->m2_buf[0]);
        /* Stores the display data using the display mode 3. */
        buf_id = 0u;
        valid_data = 0u;
        for (i = 0u; i < DSP_TFT_M3_AUDIO_SAMPLE_PER_100MS; i++) {
            /* Calculates the average of 2 channels. */
            total_val = p_aud->req_buf[buf_id] + p_aud->req_buf[buf_id + 1u];
            new_data[i] = (int16_t)((uint32_t)total_val >> SHIFT_1BIT_SIZE);
            buf_id += (DSP_TFT_M2_AUDIO_BUF_SIZE / DSP_TFT_M3_AUDIO_SAMPLE_PER_100MS);
            /* Checks the zero data */
            valid_data |= (uint32_t)new_data[i];
        }
        update_flag = false;
        if (p_com->play_stat == SYS_PLAYSTAT_PAUSE) {
            p_aud->m3_pause_flag = true;
            if (valid_data == 0u) {
                /* Current sampling data are not used. */
            } else {
                update_flag = true;
            }
        } else if (p_com->play_stat == SYS_PLAYSTAT_PLAY) {
            if ((p_aud->m3_pause_flag == true) && 
                (p_aud->m3_sample_cnt > (p_aud->m3_target_cnt + DSP_TFT_M3_AUDIO_SAMPLE_PER_100MS))) {
                /* Current sampling data are not used. */
            } else if ((p_aud->m3_pause_flag == true) && (valid_data == 0u)) {
                /* Current sampling data are not used. */
                p_aud->m3_pause_flag = false;
            } else {
                update_flag = true;
                p_aud->m3_pause_flag = false;
            }
        } else {
            p_aud->m3_pause_flag = false;
        }
        if (update_flag == true) {
            if (p_aud->m3_buf_cnt >= DSP_TFT_M3_AUDIO_BUF_SIZE) {
                p_aud->m3_buf_cnt = DSP_TFT_M3_AUDIO_BUF_SIZE - DSP_TFT_M3_AUDIO_SAMPLE_PER_100MS;
                for (i = 0u; i < p_aud->m3_buf_cnt; i++) {
                    p_aud->m3_buf[i] = p_aud->m3_buf[i + DSP_TFT_M3_AUDIO_SAMPLE_PER_100MS];
                }
            }
            for (i = 0u; i < DSP_TFT_M3_AUDIO_SAMPLE_PER_100MS; i++) {
                p_aud->m3_buf[p_aud->m3_buf_cnt] = new_data[i];
                p_aud->m3_buf_cnt++;
            }
            p_aud->m3_sample_cnt += DSP_TFT_M3_AUDIO_SAMPLE_PER_100MS;
            p_aud->m3_target_cnt += DSP_TFT_M3_AUDIO_SAMPLE_PER_100MS;
        }
    }
}

/** Converts the layer number of TFT module into the layer number of DisplayBase class.
 *
 *  @param layer_id The number of the display layer of TFT module.
 *
 *  @returns 
 *    Returns the layer number of DisplayBase class.
 */
static DisplayBase::graphics_layer_t convert_layer_id(const uint32_t layer_id)
{
    DisplayBase::graphics_layer_t   ret;

    switch (layer_id) {
        case DSP_TFT_LAYER_1:
            ret = DisplayBase::GRAPHICS_LAYER_1;
            break;
        case DSP_TFT_LAYER_0:
        default:
            ret = DisplayBase::GRAPHICS_LAYER_0;
            break;
    }
    return ret;
}

/** Swaps the frame buffers
 *
 *  @param p_info Pointer to VRAM structure
 */
static void swap_frame_buffer(dsp_tftlayer_t * const p_info)
{
    uint32_t                        *p_tmp;
    
    if (p_info != NULL) {
        p_tmp = p_info->p_disp_buf;
        p_info->p_disp_buf = p_info->p_back_buf;
        p_info->p_back_buf = p_tmp;
    }
}