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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers audio_out.cpp Source File

audio_out.cpp

00001 /*******************************************************************************
00002 * DISCLAIMER
00003 * This software is supplied by Renesas Electronics Corporation and is only
00004 * intended for use with Renesas products. No other uses are authorized. This
00005 * software is owned by Renesas Electronics Corporation and is protected under
00006 * all applicable laws, including copyright laws.
00007 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
00008 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
00009 * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
00010 * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
00011 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
00012 * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
00013 * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
00014 * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
00015 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
00016 * Renesas reserves the right, without notice, to make changes to this software
00017 * and to discontinue the availability of this software. By using this software,
00018 * you agree to the additional terms and conditions found by accessing the
00019 * following link:
00020 * http://www.renesas.com/disclaimer*
00021 * Copyright (C) 2015 Renesas Electronics Corporation. All rights reserved.
00022 *******************************************************************************/
00023 
00024 #include "mbed.h"
00025 #include "rtos.h"
00026 #include "misratypes.h"
00027 #include "r_errno.h"
00028 #include "decode.h"
00029 #include "audio_out.h"
00030 #include "display.h"
00031 #include "TLV320_RBSP.h"
00032 
00033 /*--- Macro definition of mbed-rtos mail ---*/
00034 #define MAIL_QUEUE_SIZE     (12)    /* Queue size */
00035 #define MAIL_PARAM_NUM      (3)     /* Elements number of mail parameter array */
00036 
00037 /* aud_mail_t */
00038 #define MAIL_PARAM0         (0)     /* Index number of mail parameter array */
00039 #define MAIL_PARAM1         (1)     /* Index number of mail parameter array */
00040 #define MAIL_PARAM2         (2)     /* Index number of mail parameter array */
00041 
00042 #define MAIL_PARAM_NON      (0u)    /* Value of unused element of mail parameter array */
00043 
00044 /* mail_id = AUD_MAILID_DATA_OUT */
00045 #define MAIL_DATA_OUT_CB            (MAIL_PARAM0)   /* Callback function */
00046 
00047 /* mail_id = AUD_MAILID_ZERO_OUT : No parameter */
00048 
00049 /* mail_id = AUD_MAILID_SCUX_READ_FIN */
00050 #define MAIL_SCUX_READ_RESULT       (MAIL_PARAM0)   /* Result of the process */
00051 #define MAIL_SCUX_READ_BUF_INDEX    (MAIL_PARAM1)   /* Index number of PCM buffer */
00052 #define MAIL_SCUX_READ_BYTE_NUM     (MAIL_PARAM2)   /* Byte number of PCM data */
00053 
00054 /* mail_id = AUD_MAILID_PCM_OUT_FIN */
00055 #define MAIL_PCM_OUT_RESULT         (MAIL_PARAM0)   /* Result of the process */
00056 #define MAIL_PCM_OUT_BUF_INDEX      (MAIL_PARAM1)   /* Index number of PCM buffer */
00057 
00058 /* mail_id = AUD_MAILID_GET_AUDIO */
00059 #define MAIL_GET_AUDIO_CB           (MAIL_PARAM0)   /* Callback function */
00060 #define MAIL_GET_AUDIO_BUF          (MAIL_PARAM1)   /* Pointer to the display buffer array */
00061 #define MAIL_GET_AUDIO_NUM          (MAIL_PARAM2)   /* Elements number of the display buffer array */
00062 
00063 /*--- Macro definition of PCM buffer ---*/
00064 #define UNIT_TIME_MS                (10u)   /* Unit time of PCM data processing (ms) */
00065 #define SEC_TO_MSEC                 (1000u)
00066 
00067 /* Sample number per unit time (ms) */
00068 #define SAMPLE_PER_UNIT_MS          ((UNIT_TIME_MS * DEC_OUTPUT_SAMPLE_RATE) / SEC_TO_MSEC)
00069 
00070 #define OUTPUT_START_TRIGGER        (3)     /* Numerical value of the trigger */
00071                                             /* to start the output of PCM data */
00072 #define OUTPUT_UPDATE_TRIGGER       (1)     /* Numerical value of the trigger */
00073                                             /* to update the output of PCM data */
00074 
00075 #define PCM_BUF_NUM                 (DEC_SCUX_READ_NUM)
00076 #define TOTAL_SAMPLE_NUM            (SAMPLE_PER_UNIT_MS * DEC_OUTPUT_CHANNEL_NUM)
00077 
00078 /*--- Macro definition of TLV320_RBSP ---*/
00079 #define AUDIO_POWER_MIC_OFF         (0x02)  /* Microphone input :OFF */
00080 #define AUDIO_INT_LEVEL             (0x80)
00081 #define AUDIO_READ_NUM              (0)
00082 #define AUDIO_WRITE_NUM             (PCM_BUF_NUM)
00083 #define ERR_MSG_TLV320_RBSP_WRITE   "\nError: TLV320_RBSP::write()\n"
00084 
00085 /* 4 bytes aligned. No cache memory. */
00086 #define NC_BSS_SECT                 __attribute__((section("NC_BSS"),aligned(4)))
00087 #define ERR_MSG_RECV_ILLEGAL_MAIL   "\nError: aud_thread function received illegal mail.\n"
00088 
00089 /*--- User defined types of mbed-rtos mail ---*/
00090 typedef enum {
00091     AUD_MAILID_DUMMY = 0,
00092     AUD_MAILID_DATA_OUT,            /* Requests the output of PCM data. */
00093     AUD_MAILID_ZERO_OUT,            /* Requests the output of zero data. */
00094     AUD_MAILID_SCUX_READ_FIN,       /* Finished the reading process of SCUX. */
00095     AUD_MAILID_PCM_OUT_FIN,         /* Finished the output of data. */
00096     AUD_MAILID_GET_AUDIO,           /* Requests the audio data acquisition. */
00097     AUD_MAILID_NUM
00098 } AUD_MAIL_ID;
00099 
00100 typedef struct {
00101     AUD_MAIL_ID     mail_id;
00102     uint32_t        param[MAIL_PARAM_NUM];
00103 } aud_mail_t;
00104 
00105 /*--- User defined types of audio output thread ---*/
00106 /* The control data of PCM buffer. */
00107 typedef struct {
00108     uint32_t    pcm_buf_index;      /* Index of PCM buffer array */
00109     uint32_t    pcm_buf_remain_cnt; /* Counter of the remain elements in PCM buffer array */
00110     uint32_t    pcm_stock_cnt;      /* Counter of the stock elements in PCM buffer array */
00111     uint32_t    output_trg_cnt;     /* Number of the trigger to start the output of PCM data */
00112 } pcm_buf_ctrl_t;
00113 
00114 static Mail<aud_mail_t, MAIL_QUEUE_SIZE> mail_box;
00115 
00116 static void init_pcm_buf(pcm_buf_ctrl_t * const p_ctrl);
00117 static bool read_scux(int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t buf_id);
00118 static bool write_audio(TLV320_RBSP * const p_audio, int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t buf_id);
00119 static void read_callback(void * p_data, int32_t result, void * p_app_data);
00120 static void pcm_out_callback(void * p_data, int32_t result, void * p_app_data);
00121 static bool send_mail(const AUD_MAIL_ID mail_id, const uint32_t param0, 
00122                             const uint32_t param1, const uint32_t param2);
00123 static bool recv_mail(AUD_MAIL_ID * const p_mail_id, uint32_t * const p_param0, 
00124                         uint32_t * const p_param1, uint32_t * const p_param2);
00125 
00126 void aud_thread(void const *argument)
00127 {
00128     pcm_buf_ctrl_t              buf_ctrl;
00129     pcm_buf_ctrl_t              * const p_ctrl = &buf_ctrl;
00130     bool                        scux_read_enable = false;
00131     AUD_MAIL_ID                 mail_type;
00132     uint32_t                    mail_param[MAIL_PARAM_NUM];
00133     bool                        result;
00134     AUD_CbDataOut               cb_data_out;
00135     uint32_t                    i;
00136     uint32_t                    buf_id;
00137     int32_t                     *p_buf;
00138     uint32_t                    byte_cnt;
00139     AUD_CbAudioData             cb_audio_data;
00140     static int32_t NC_BSS_SECT  pcm_buf[PCM_BUF_NUM][TOTAL_SAMPLE_NUM];
00141     static TLV320_RBSP          audio(P10_13, I2C_SDA, I2C_SCL, P4_4, P4_5, P4_7,
00142                                   P4_6, AUDIO_INT_LEVEL, AUDIO_WRITE_NUM, AUDIO_READ_NUM);
00143 
00144     UNUSED_ARG(argument);
00145 
00146     /* Initializes the control data of PCM buffer. */
00147     init_pcm_buf(p_ctrl);
00148 
00149     /* Sets the output of PCM data using TLV320_RBSP. */
00150     (void) audio.format(DEC_OUTPUT_BITS_PER_SAMPLE);
00151     (void) audio.frequency(DEC_OUTPUT_SAMPLE_RATE);
00152     audio.power(AUDIO_POWER_MIC_OFF);
00153     while (1) {
00154         result = recv_mail(&mail_type, &mail_param[MAIL_PARAM0], 
00155                     &mail_param[MAIL_PARAM1], &mail_param[MAIL_PARAM2]);
00156         if (result == true) {
00157             switch (mail_type) {
00158                 case AUD_MAILID_DATA_OUT:        /* Requests the output of PCM data. */
00159                     cb_data_out = (AUD_CbDataOut)mail_param[MAIL_DATA_OUT_CB];
00160                     if (scux_read_enable != true) {
00161                         scux_read_enable = true;
00162                         result = true;
00163                         for (i = 0; (i < p_ctrl->pcm_buf_remain_cnt) && (result == true); i++) {
00164                             buf_id = (p_ctrl->pcm_buf_index + i) % PCM_BUF_NUM;
00165                             result = read_scux(&pcm_buf[buf_id], buf_id);
00166                         }
00167                         if (result == true) {
00168                             p_ctrl->output_trg_cnt = OUTPUT_START_TRIGGER;
00169                         }
00170                     } else {
00171                         result = false;
00172                     }
00173                     cb_data_out(result);
00174                     break;
00175                 case AUD_MAILID_ZERO_OUT:        /* Requests the output of zero data. */
00176                     scux_read_enable = false;
00177                     break;
00178                 case AUD_MAILID_SCUX_READ_FIN:   /* Finished the reading process of SCUX. */
00179                     buf_id = mail_param[MAIL_SCUX_READ_BUF_INDEX];
00180                     byte_cnt = mail_param[MAIL_SCUX_READ_BYTE_NUM];
00181                     if ((buf_id < PCM_BUF_NUM) && (byte_cnt <= sizeof(pcm_buf[0]))) {
00182                         if (byte_cnt < sizeof(pcm_buf[0])) {
00183                             /* End of stream */
00184                             /* Fills the remain area of PCM buffer with 0. */
00185                             p_buf = &pcm_buf[buf_id][byte_cnt/sizeof(pcm_buf[0][0])];
00186                             (void) memset(p_buf, 0, sizeof(pcm_buf[0]) - byte_cnt);
00187                             p_ctrl->output_trg_cnt = OUTPUT_UPDATE_TRIGGER;
00188                         }
00189                         p_ctrl->pcm_stock_cnt++;
00190                         if (p_ctrl->pcm_stock_cnt >= p_ctrl->output_trg_cnt) {
00191                             /* Starts the output of PCM data. */
00192                             result = true;
00193                             for (i = 0; (i < p_ctrl->pcm_stock_cnt) && (result == true); i++) {
00194                                 buf_id = (p_ctrl->pcm_buf_index + i) % PCM_BUF_NUM;
00195                                 result = write_audio(&audio, &pcm_buf[buf_id], buf_id);
00196                                 if (result == true) {
00197                                     p_ctrl->pcm_buf_remain_cnt--;
00198                                 }
00199                             }
00200                             if (result != true) {
00201                                 /* Unexpected cases : Output error message to PC */
00202                                 (void) dsp_notify_print_string(ERR_MSG_TLV320_RBSP_WRITE);
00203                             }
00204                             p_ctrl->pcm_buf_index  = 
00205                                         (p_ctrl->pcm_buf_index + p_ctrl->pcm_stock_cnt) % PCM_BUF_NUM;
00206                             p_ctrl->pcm_stock_cnt  = 0u;
00207                             p_ctrl->output_trg_cnt = OUTPUT_UPDATE_TRIGGER;
00208                         }
00209                     } else {
00210                         /* Unexpected cases : This is fail-safe processing. */
00211                         scux_read_enable = false;
00212                     }
00213                     break;
00214                 case AUD_MAILID_PCM_OUT_FIN:     /* Finished the output of data. */
00215                     p_ctrl->pcm_buf_remain_cnt++;
00216                     if ((int32_t)mail_param[MAIL_PCM_OUT_RESULT] == true) {
00217                         buf_id = mail_param[MAIL_PCM_OUT_BUF_INDEX];
00218                         if (scux_read_enable == true) {
00219                             (void) read_scux(&pcm_buf[buf_id], buf_id);
00220                         } else {
00221                             (void) memset(&pcm_buf[buf_id], 0, sizeof(pcm_buf[0]));
00222                         }
00223                     } else {
00224                         /* Unexpected cases : Output error message to PC */
00225                         (void) dsp_notify_print_string(ERR_MSG_TLV320_RBSP_WRITE);
00226                     }
00227                     break;
00228                 case AUD_MAILID_GET_AUDIO:
00229                     cb_audio_data = (AUD_CbAudioData)mail_param[MAIL_GET_AUDIO_CB];
00230                     if (cb_audio_data != NULL) {
00231                         if (p_ctrl->pcm_buf_index > 0u) {
00232                             buf_id = p_ctrl->pcm_buf_index - 1u;
00233                         } else {
00234                             buf_id = PCM_BUF_NUM - 1u;
00235                         }
00236                         cb_audio_data(true, (int16_t*)mail_param[MAIL_GET_AUDIO_BUF], 
00237                             mail_param[MAIL_GET_AUDIO_NUM], pcm_buf[buf_id], sizeof(pcm_buf[0])/sizeof(pcm_buf[0][0]));
00238                     }
00239                     break;
00240                 default:
00241                     /* Unexpected cases : Output error message to PC */
00242                     (void) dsp_notify_print_string(ERR_MSG_RECV_ILLEGAL_MAIL);
00243                     break;
00244             }
00245         }
00246     }
00247 }
00248 
00249 bool aud_req_data_out(const AUD_CbDataOut p_cb)
00250 {
00251     bool    ret = false;
00252 
00253     if (p_cb != NULL) {
00254         ret = send_mail(AUD_MAILID_DATA_OUT, (uint32_t)p_cb, MAIL_PARAM_NON, MAIL_PARAM_NON);
00255     }
00256     return ret;
00257 }
00258 
00259 bool aud_req_zero_out(void)
00260 {
00261     bool    ret = false;
00262 
00263     ret = send_mail(AUD_MAILID_ZERO_OUT, MAIL_PARAM_NON, MAIL_PARAM_NON, MAIL_PARAM_NON);
00264     return ret;
00265 }
00266 
00267 bool aud_get_audio_data(const AUD_CbAudioData p_cb, int16_t * const p_buf, const uint32_t buf_num)
00268 {
00269     bool    ret = false;
00270 
00271     if ((p_cb != NULL) && (p_buf != NULL) && (buf_num > 0u)) {
00272         ret = send_mail(AUD_MAILID_GET_AUDIO, (uint32_t)p_cb, (uint32_t)p_buf, (uint32_t)buf_num);
00273     }
00274     return ret;
00275 }
00276 
00277 /** Initialises the control data of PCM buffer
00278  *
00279  *  @param p_ctrl Pointer to the control data of PCM buffer.
00280  */
00281 static void init_pcm_buf(pcm_buf_ctrl_t * const p_ctrl)
00282 {
00283     if (p_ctrl != NULL) {
00284         p_ctrl->pcm_buf_index = 0u;
00285         p_ctrl->pcm_buf_remain_cnt = PCM_BUF_NUM;
00286         p_ctrl->pcm_stock_cnt = 0u;
00287         p_ctrl->output_trg_cnt = OUTPUT_START_TRIGGER;
00288     }
00289 }
00290 
00291 /** Gets PCM data from SCUX driver
00292  *
00293  *  @param p_buf Pointer to PCM buffer array to store the data.
00294  *  @param buf_id The control ID of PCM buffer.
00295  *
00296  *  @returns 
00297  *    Results of process. true is success. false is failure.
00298  */
00299 static bool read_scux(int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t buf_id)
00300 {
00301     bool                ret = false;
00302     rbsp_data_conf_t    cb_conf = {
00303         &read_callback,
00304         NULL
00305     };
00306 
00307     if ((p_buf != NULL) && (buf_id < PCM_BUF_NUM)) {
00308         cb_conf.p_app_data = (void *)buf_id;
00309         ret = dec_scux_read(p_buf, sizeof(p_buf[0]), &cb_conf);
00310     }
00311     return ret;
00312 }
00313 
00314 /** Writes PCM data to TLV320_RBSP driver
00315  *
00316  *  @param p_buf Pointer to PCM buffer array.
00317  *  @param buf_id The control ID of PCM buffer.
00318  *
00319  *  @returns 
00320  *    Results of process. true is success. false is failure.
00321  */
00322 static bool write_audio(TLV320_RBSP * const p_audio, int32_t (* const p_buf)[TOTAL_SAMPLE_NUM], const uint32_t buf_id)
00323 {
00324     bool                ret = false;
00325     int32_t             result;
00326     rbsp_data_conf_t    cb_conf = {
00327         &pcm_out_callback,
00328         NULL
00329     };
00330 
00331     if ((p_audio != NULL) && (p_buf != NULL) && (buf_id < PCM_BUF_NUM)) {
00332         cb_conf.p_app_data = (void *)buf_id;
00333         result = p_audio->write(p_buf, sizeof(p_buf[0]), &cb_conf);
00334         if (result == ESUCCESS) {
00335             ret = true;
00336         }
00337     }
00338     return ret;
00339 }
00340 
00341 /** Callback function of SCUX driver
00342  *
00343  *  @param p_data Pointer to PCM byffer array.
00344  *  @param result Result of the process.
00345  *  @param p_app_data The control ID of PCM buffer.
00346  */
00347 static void read_callback(void * p_data, int32_t result, void * p_app_data)
00348 {
00349     const uint32_t  buf_id = (uint32_t)p_app_data;
00350     uint32_t        read_byte;
00351     bool            flag_result;
00352 
00353     UNUSED_ARG(p_data);
00354     if (result > 0) {
00355         flag_result = true;
00356         read_byte = (uint32_t)result;
00357     } else {
00358         flag_result = false;
00359         read_byte = 0u;
00360     }
00361     (void) send_mail(AUD_MAILID_SCUX_READ_FIN, (uint32_t)flag_result, buf_id, read_byte);
00362 }
00363 
00364 /** Callback function of TLV320_RBSP driver
00365  *
00366  *  @param p_data Pointer to PCM byffer array.
00367  *  @param result Result of the process.
00368  *  @param p_app_data The control ID of PCM buffer.
00369  */
00370 static void pcm_out_callback(void * p_data, int32_t result, void * p_app_data)
00371 {
00372     const uint32_t  buf_id = (uint32_t)p_app_data;
00373     bool            flag_result;
00374 
00375     UNUSED_ARG(p_data);
00376     if (result > 0) {
00377         flag_result = true;
00378     } else {
00379         flag_result = false;
00380     }
00381     (void) send_mail(AUD_MAILID_PCM_OUT_FIN, (uint32_t)flag_result, buf_id, MAIL_PARAM_NON);
00382 }
00383 
00384 /** Sends the mail to Decode thread
00385  *
00386  *  @param mail_id Mail ID
00387  *  @param param0 Parameter 0 of this mail
00388  *  @param param1 Parameter 1 of this mail
00389  *  @param param2 Parameter 2 of this mail
00390  *
00391  *  @returns 
00392  *    Results of process. true is success. false is failure.
00393  */
00394 static bool send_mail(const AUD_MAIL_ID mail_id, const uint32_t param0, 
00395                             const uint32_t param1, const uint32_t param2)
00396 {
00397     bool            ret = false;
00398     osStatus        stat;
00399     aud_mail_t      * const p_mail = mail_box.alloc();
00400 
00401     if (p_mail != NULL) {
00402         p_mail->mail_id = mail_id;
00403         p_mail->param[MAIL_PARAM0] = param0;
00404         p_mail->param[MAIL_PARAM1] = param1;
00405         p_mail->param[MAIL_PARAM2] = param2;
00406         stat = mail_box.put(p_mail);
00407         if (stat == osOK) {
00408             ret = true;
00409         } else {
00410             (void) mail_box.free(p_mail);
00411         }
00412     }
00413     return ret;
00414 }
00415 
00416 /** Receives the mail to Decode thread
00417  *
00418  *  @param p_mail_id Pointer to the variable to store the mail ID
00419  *  @param p_param0 Pointer to the variable to store the parameter 0 of this mail
00420  *  @param p_param1 Pointer to the variable to store the parameter 1 of this mail
00421  *  @param p_param2 Pointer to the variable to store the parameter 2 of this mail
00422  *
00423  *  @returns 
00424  *    Results of process. true is success. false is failure.
00425  */
00426 static bool recv_mail(AUD_MAIL_ID * const p_mail_id, uint32_t * const p_param0, 
00427                         uint32_t * const p_param1, uint32_t * const p_param2)
00428 {
00429     bool            ret = false;
00430     osEvent         evt;
00431     aud_mail_t      *p_mail;
00432     
00433     if ((p_mail_id != NULL) && (p_param0 != NULL) && 
00434         (p_param1 != NULL) && (p_param2 != NULL)) {
00435         evt = mail_box.get();
00436         if (evt.status == osEventMail) {
00437             p_mail = (aud_mail_t *)evt.value.p;
00438             if (p_mail != NULL) {
00439                 *p_mail_id = p_mail->mail_id;
00440                 *p_param0 = p_mail->param[MAIL_PARAM0];
00441                 *p_param1 = p_mail->param[MAIL_PARAM1];
00442                 *p_param2 = p_mail->param[MAIL_PARAM2];
00443                 ret = true;
00444             }
00445             (void) mail_box.free(p_mail);
00446         }
00447     }
00448     return ret;
00449 }