ソフト S/PDIF トランスミッタ (14)

STM32CubeMX で (STM32F4xx 用の) C 初期化コードを生成すると、次のファイル、

  • stm32f4xx_hal_conf.h
  • stm32f4xx_it.h
  • main.c
  • stm32f4xx_hal_msp.c
  • stm32f4xx_it.c

が作られます。
このうち、「.c」ファイルにはユーザが記述を追加できる領域があり、「お約束」に従って記述しておけば、初期化コードを新たに生成し直してもユーザ記述部分は新しいファイルに受け継がれるようになっています。
今回はユーザ・コードを追加する必要があったのは「main.c」だけなので、「main.c」のソースだけを示します。
STM32CubeMX で生成した「カラ」の状態の「main.c」を下のリストで置き換えてください。
今回はソース・リストのみ掲載し、補足の説明は次回行います。

/**
  ******************************************************************************
  * File Name          : main.c
  * Date               : 03/09/2014 18:38:07
  * Description        : Main program body
  ******************************************************************************
  *
  * COPYRIGHT(c) 2014 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* Private variables ---------------------------------------------------------*/
I2S_HandleTypeDef hi2s3;
DMA_HandleTypeDef hdma_spi3_tx;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN 0 */

// Software S/PDIF transmitter using SPI/I2S and DMA
// 2014/08/26 by pcm1723

// uncomment following line to use BMC table in FLASH to save RAM
//#define BMC_TAB_IN_ROM 1

//#define DAC_TEST 1

// LD2 User LED (green) on 'D13' (PA5) pin
#define IDLE_LED_ON     HAL_GPIO_WritePin(GPIOA,  GPIO_PIN_5, GPIO_PIN_SET)
#define IDLE_LED_OFF    HAL_GPIO_WritePin(GPIOA,  GPIO_PIN_5, GPIO_PIN_RESET)
#define IDLE_LED_TOGGLE HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5)

// S/PDIF frame/block definition
#define FRAMES_PER_BLOCK   192 // frames per block
#define W16_PER_SUBFRAME     4 // 16-bit halfword count per subframe
#define W16_PER_FRAME        8 // 16-bit halfword count per frame 
#define W16_PER_BLOCK     (W16_PER_FRAME * FRAMES_PER_BLOCK) // 16-bit halfword count per block
#define SPDIF_TXBUF_INDMAX (sizeof(spdif_txbuf)/sizeof(int16_t)) // number of 16-bit halfword in TX buffer

// SPI/I2S module definition for S/PDIF TX
#define SPDIF      SPI3         // module instance name
#define hSPDIF     hi2s3        // handle object 
#define hSPDIF_dma hdma_spi3_tx // handle object for DMA

// S/PDIF TX buffer index structure
typedef struct tag_spdif_txind_t {
// room for output data (count in terms of halfword)
  volatile uint16_t room; 
// S/PDIF TX buffer pointer
  volatile uint16_t *ptr; 
} spdif_txind_t;

static spdif_txind_t spdif_txind;

// biphase mark code bitmaps
//
// bitmap for        0 0 0 0
//                   --__--__
#define BMC_0000 (0xCC)

// bitmap for        1 0 0 0
//                   -_--__-- 
#define BMC_1000 (0xB3)

// bitmap for        0 0 1 1
//                   --__-_-_ 
#define BMC_0011 (0xCA)

// bitmap for UVCP bits = 0 0 0 0
#define BMC_VUCP_0000 (BMC_0000 << 8)

// bitmap for UVCP bits = 0 0 1 1
#define BMC_VUCP_0011 (BMC_0011 << 8)

// bitmap for preamble 'B' (frame 0 L-ch indication)
//                         ---_-___
#define BMC_PREAMBLE_B (0xE8)

// bitmap for preamble 'W' (R-ch)
//                         ---__-__
#define BMC_PREAMBLE_W (0xE4)

// bitmap for preamble 'M' (L-ch)
//                         ---___-_
#define BMC_PREAMBLE_M (0xE2)

// bitmap for                0 0 0 0 0 0 0 0
//                           --__--__--__--__
#define BMC_0000_0000 (0xCCCC)

// bitmap for                1 0 0 0 0 0 0 0
//                           -_--__--__--__-- 
#define BMC_1000_0000 (0xB333)

// S/PDIF channel status bits
//
// b0     = 0  : PRO=0 (consumer)
// b1     = 0  : AUDIO#=0 (digital audio)
// b2     = 1  : Copy=1 (permitted)
// b3:4:5 = 0  : Pre-emphasis=0 (none)
// b7:6   = 0  : Mode=0 (defines byte1-3)
//
// b8:9:10:11:12:13:14 = 0  : General
// b15                 = 0  : Generation=0 (no indication)
//
// b16:17:18:19 = 0  : Source  Number=0 (unspecified)
// b20:21:22:23 = 0  : Channel Number=0 (unspecified)
//
// b24:25:26:27 = 4  : fs = 48 kHz
// b28:29       = 0  : Clock Acuracy=0 (Level II, +-1000 ppm, default)
// b30:31       = 0  : Reserved

// first 32 bits of channel status (copy permitted, fs = 48 kHz)
#define CH_STATUS_BITS (0x20000040UL)

// channel status data mask
#define CH_STAT_MASK (0x80000000UL)

#define HAS_SPDIF_TXBUF_ROOM (0 < spdif_txind.room)

// S/PDIF TX buffer in RAM (1 block)
uint16_t spdif_txbuf[W16_PER_BLOCK]; 

const uint8_t sync_tab[2][2] = {
  { BMC_PREAMBLE_M, BMC_PREAMBLE_W }, // preamble M/W for L/R (not frame 0)
  { BMC_PREAMBLE_B, BMC_PREAMBLE_W }  // preamble B/W for L/R (frame 0 only)
}; // const uint8_t sync_tab[][]

const uint16_t vucp_tab[2] = {
  BMC_VUCP_0000, // bitmap for C=0, P=0
  BMC_VUCP_0011  // bitmap for C=1, P=1
}; // const uint16_t vucp_tab[]

// Biphase Mark Code (BMC) table for byte (8-bit) data
// ('0' ending pattern)
#if defined(BMC_TAB_IN_ROM)
const uint16_t bmc8b[256] = {
  0xCCCC, 0x4CCC, 0x2CCC, 0xACCC, // 0x00..0x03
  0x34CC, 0xB4CC, 0xD4CC, 0x54CC, // 0x04..0x07
  0x32CC, 0xB2CC, 0xD2CC, 0x52CC, // 0x08..0x0B
  0xCACC, 0x4ACC, 0x2ACC, 0xAACC, // 0x0C..0x0F
  0x334C, 0xB34C, 0xD34C, 0x534C, // 0x10..0x13
  0xCB4C, 0x4B4C, 0x2B4C, 0xAB4C, // 0x14..0x17
  0xCD4C, 0x4D4C, 0x2D4C, 0xAD4C, // 0x18..0x1B
  0x354C, 0xB54C, 0xD54C, 0x554C, // 0x1C..0x1F
  0x332C, 0xB32C, 0xD32C, 0x532C, // 0x20..0x23
  0xCB2C, 0x4B2C, 0x2B2C, 0xAB2C, // 0x24..0x27
  0xCD2C, 0x4D2C, 0x2D2C, 0xAD2C, // 0x28..0x2B
  0x352C, 0xB52C, 0xD52C, 0x552C, // 0x2C..0x2F
  0xCCAC, 0x4CAC, 0x2CAC, 0xACAC, // 0x30..0x33
  0x34AC, 0xB4AC, 0xD4AC, 0x54AC, // 0x34..0x37
  0x32AC, 0xB2AC, 0xD2AC, 0x52AC, // 0x38..0x3B
  0xCAAC, 0x4AAC, 0x2AAC, 0xAAAC, // 0x3C..0x3F
  0x3334, 0xB334, 0xD334, 0x5334, // 0x40..0x43
  0xCB34, 0x4B34, 0x2B34, 0xAB34, // 0x44..0x47
  0xCD34, 0x4D34, 0x2D34, 0xAD34, // 0x48..0x4B
  0x3534, 0xB534, 0xD534, 0x5534, // 0x4C..0x4F
  0xCCB4, 0x4CB4, 0x2CB4, 0xACB4, // 0x50..0x53
  0x34B4, 0xB4B4, 0xD4B4, 0x54B4, // 0x54..0x57
  0x32B4, 0xB2B4, 0xD2B4, 0x52B4, // 0x58..0x5B
  0xCAB4, 0x4AB4, 0x2AB4, 0xAAB4, // 0x5C..0x5F
  0xCCD4, 0x4CD4, 0x2CD4, 0xACD4, // 0x60..0x63
  0x34D4, 0xB4D4, 0xD4D4, 0x54D4, // 0x64..0x67
  0x32D4, 0xB2D4, 0xD2D4, 0x52D4, // 0x68..0x6B
  0xCAD4, 0x4AD4, 0x2AD4, 0xAAD4, // 0x6C..0x6F
  0x3354, 0xB354, 0xD354, 0x5354, // 0x70..0x73
  0xCB54, 0x4B54, 0x2B54, 0xAB54, // 0x74..0x77
  0xCD54, 0x4D54, 0x2D54, 0xAD54, // 0x78..0x7B
  0x3554, 0xB554, 0xD554, 0x5554, // 0x7C..0x7F
  0x3332, 0xB332, 0xD332, 0x5332, // 0x80..0x83
  0xCB32, 0x4B32, 0x2B32, 0xAB32, // 0x84..0x87
  0xCD32, 0x4D32, 0x2D32, 0xAD32, // 0x88..0x8B
  0x3532, 0xB532, 0xD532, 0x5532, // 0x8C..0x8F
  0xCCB2, 0x4CB2, 0x2CB2, 0xACB2, // 0x90..0x93
  0x34B2, 0xB4B2, 0xD4B2, 0x54B2, // 0x94..0x97
  0x32B2, 0xB2B2, 0xD2B2, 0x52B2, // 0x98..0x9B
  0xCAB2, 0x4AB2, 0x2AB2, 0xAAB2, // 0x9C..0x9F
  0xCCD2, 0x4CD2, 0x2CD2, 0xACD2, // 0xA0..0xA3
  0x34D2, 0xB4D2, 0xD4D2, 0x54D2, // 0xA4..0xA7
  0x32D2, 0xB2D2, 0xD2D2, 0x52D2, // 0xA8..0xAB
  0xCAD2, 0x4AD2, 0x2AD2, 0xAAD2, // 0xAC..0xAF
  0x3352, 0xB352, 0xD352, 0x5352, // 0xB0..0xB3
  0xCB52, 0x4B52, 0x2B52, 0xAB52, // 0xB4..0xB7
  0xCD52, 0x4D52, 0x2D52, 0xAD52, // 0xB8..0xBB
  0x3552, 0xB552, 0xD552, 0x5552, // 0xBC..0xBF
  0xCCCA, 0x4CCA, 0x2CCA, 0xACCA, // 0xC0..0xC3
  0x34CA, 0xB4CA, 0xD4CA, 0x54CA, // 0xC4..0xC7
  0x32CA, 0xB2CA, 0xD2CA, 0x52CA, // 0xC8..0xCB
  0xCACA, 0x4ACA, 0x2ACA, 0xAACA, // 0xCC..0xCF
  0x334A, 0xB34A, 0xD34A, 0x534A, // 0xD0..0xD3
  0xCB4A, 0x4B4A, 0x2B4A, 0xAB4A, // 0xD4..0xD7
  0xCD4A, 0x4D4A, 0x2D4A, 0xAD4A, // 0xD8..0xDB
  0x354A, 0xB54A, 0xD54A, 0x554A, // 0xDC..0xDF
  0x332A, 0xB32A, 0xD32A, 0x532A, // 0xE0..0xE3
  0xCB2A, 0x4B2A, 0x2B2A, 0xAB2A, // 0xE4..0xE7
  0xCD2A, 0x4D2A, 0x2D2A, 0xAD2A, // 0xE8..0xEB
  0x352A, 0xB52A, 0xD52A, 0x552A, // 0xEC..0xEF
  0xCCAA, 0x4CAA, 0x2CAA, 0xACAA, // 0xF0..0xF3
  0x34AA, 0xB4AA, 0xD4AA, 0x54AA, // 0xF4..0xF7
  0x32AA, 0xB2AA, 0xD2AA, 0x52AA, // 0xF8..0xFB
  0xCAAA, 0x4AAA, 0x2AAA, 0xAAAA, // 0xFC..0xFF
}; // const uint16_t bmc8b[]
#else
uint16_t bmc8b[256];  // BMC table in RAM
#endif // #if defined(BMC_TAB_IN_ROM)

// user callback for DMA half complete
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
  if (SPDIF == hi2s->Instance) { // is SPI/I2S device for SPDIF?
    spdif_txind.room = (SPDIF_TXBUF_INDMAX / 2);
// TX buffer pointer (the first half)
    spdif_txind.ptr  = &(spdif_txbuf[0]); 
  } //
} // void HAL_I2S_TxHalfCpltCallback()

// user callback for DMA (full) complete
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
  if (SPDIF == hi2s->Instance) { // is SPI/I2S device for SPDIF?
    spdif_txind.room = (SPDIF_TXBUF_INDMAX / 2);
// TX buffer pointer (the second half)
    spdif_txind.ptr  = &(spdif_txbuf[SPDIF_TXBUF_INDMAX / 2]); 
  } //
} // HAL_I2S_TxCpltCallback()

// build biphase mark code table for byte data
#if !defined(BMC_TAB_IN_ROM)
void setup_bmc8b( void )
{
  int i, j, b, d;
  uint16_t m; // bit pattern of biphase mark coded data
  
  for (i = 0; i < 256; i++) { // loop for 8-bit number
    m = 0; // init biphase mark code bit pattern
    b = 0; // output bit data (assume 1 start)
    d = i; // input data
    for (j = 0; j < 8; j++) { // scan for 8-bit
// bit boundary edge (always flip)     
      m <<= 1; // shift left bit patten
      b  ^= 1; // flip always for bit boundary
      m  |= b; // bit boudary edge
// data bit edge (flip for (data_bit == 1))
      m <<= 1; // shift left bit pattern
      b  ^= (1 & d); // flip / not flip output bit
      m  |= b; // data bit edge
//      
      d >>= 1; // shift right input data
    } // for (j = 0; ...
    if (0x01 & m) { // test for "1 end"
      m ^= 0xFFFF;  // invert bits to force "0 end"
    } // if (0x01 & m)
    bmc8b[i] = m; // store result in table
  } // for (i = 0; ...
} // void setup_bmc8b()
#endif

// setup S/PDIF TX buffer in RAM for specified block(s)
void setup_spdif_txbuf(int blocks, uint32_t chs, int builtin_wave)
{
  int i, j, k, m, cbit;
  
  j = 0; // index of SPDIF TX buffer array
  for (m = 0; m < blocks; m++) { // loop for block(s)
    cbit = 0;  // assume C=0 for the very last subframe of prev. block
    for (i = 0; i < (FRAMES_PER_BLOCK); i++) { // frame index (0..191)
      for (k = 0; k < 2; k++) { // subframe index (0..1)
        spdif_txbuf[j++] = ( vucp_tab[cbit]      // VUCP of prev subframe
                           | sync_tab[0 == i][k] // preamble
                           );
        spdif_txbuf[j++] = BMC_0000_0000; // AUX (4 bit) + sub_LSB (4 bit) 
        spdif_txbuf[j++] = BMC_0000_0000; // LSByte(8 bit) of audio data (0x00)
        if (builtin_wave) { // pre-encoded square wave
          if (1 & ((i + (k << 4)) >> 5)) { // 750 Hz square wave       
            spdif_txbuf[j++] = 0xB334; // MSByte(8 bit) of audio data (0x41:00 =  16640)
          } else {
            spdif_txbuf[j++] = 0xCCCA; // MSByte(8 bit) of audio data (0xC0:00 = -16384)
          } // if (1 & (i >> 5)) { ...
        } else {// silence
          spdif_txbuf[j++] = BMC_0000_0000; // MSByte(8 bit) of audio data (0x00)   
        } // if (builtin_wave) { ...
        if (0 == k) { // frame boundary for VUCP nibble
          cbit = (0 != (CH_STAT_MASK & chs)); // extract ch status bit
          chs <<= 1 ;             // shift ch status reg for next frame
        } // if (0 == k) { ...
      } // for (k = 0; ...
    } // for (i = 0; ...
  } // for (m = 0; ...
#if !defined(BMC_TAB_IN_ROM)  
  setup_bmc8b(); // build biphase mark code table  
#endif 
} // void setup_spdif_txbuf()

// encode audio data for specified number of subframe(s)
uint16_t spdif_encode_subframe_data(int16_t dat[], uint16_t nsf)
{
  int i;
  uint16_t bmc_L, bmc_H, aux; // bitmap of biphase mark code
  const uint32_t BMC_LSB_MASK = (1U << 15);
  register volatile uint16_t *p; // TX buffer pointer
  
  p = spdif_txind.ptr; // get S/PDIF TX buffer pointer
  for (i = 0; i < nsf; i++) { // for subframe(s)
// encode LSByte (d[0:7])  of audio data
    bmc_L  = bmc8b[(uint8_t) dat[i]];       
// encode MSByte (d[8:15]) of audio data
    bmc_H  = bmc8b[(uint8_t)(dat[i] >> 8)]; 
    *(p + 3)  = bmc_H; // audio data d[8:15] (8 bit)
#if (__CORTEX_M >= 0x03) // Cortex-M3/M4 processor ?
// invert bmc of d[0:7] if (0 == bmc_H[15])
    bmc_L ^= (~((int16_t)bmc_H) >> 16);   
// gimmick for Cortex-M3/M4 processor (ARMv7-M arch) to avoid conditional
    aux    = (BMC_1000_0000 ^ (((uint32_t)((int16_t)bmc_L)) >> 17));
#else // Cortex-M0 processor (ARMv6-M arch)
// invert bmc of d[0:7] if (0 == bmc_H[15])
    bmc_L ^= ((bmc_H >> 15) + 0xFFFFU);   
// straightforward implementation for Cortex-M0
    if (BMC_LSB_MASK & bmc_L) { // detect "1 start" 
      aux = BMC_0000_0000;      // no need to adjust parity
    } else {
      aux = BMC_1000_0000;      // adjust parity
    } // if (BMC_LSB_MASK & bmc_L) { ...
#endif      
// SPDIF TX buffer update for this subframe data  
// VUCP (4 bit) and preamble (4 bit) not changed (pointed by *(p))
// AUX (4 bit) + audio ext (4 bit) for parity correction
    *(p + 1)  = aux;   
    *(p + 2)  = bmc_L; // audio data d[0:7]  (8 bit)
    p        += 4;     // advance TX buffer pointer by 4
  } // for (i = 0; 
// advance S/PDIF TX buffer pointer
  spdif_txind.ptr   = p;         
// 4 halfword (64 bit) used per subframe
  spdif_txind.room -= (4 * nsf); 
  return(spdif_txind.room);
} // uint16_t spdif_encode_subframe_data()

void modify_i2s_pll( void )
{
  uint32_t i2s_pllm;

// get PLLM value from main PLL  
  i2s_pllm = (0x3F & RCC->PLLCFGR);
  __HAL_RCC_PLLI2S_DISABLE(); // stop I2S PLL
// wait for I2S PLL halted  
  while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) != RESET) {}
// set PLLM value for I2S PLL
  RCC->PLLI2SCFGR = ((~0x3F & RCC->PLLI2SCFGR) | i2s_pllm); 
  __HAL_RCC_PLLI2S_ENABLE();  // re-start I2S PLL
} // void modify_i2spll()

/* USER CODE END 0 */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_I2S3_Init(void);
static void MX_USART2_UART_Init(void);

int main(void)
{

  /* USER CODE BEGIN 1 */
  
  int16_t sfbuf[2];         // subframe data buffer
  int32_t sin_acc = 0;      
  int32_t cos_acc = 0x7e00; // initial radius

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* System interrupt init*/
  /* Sets the priority grouping field */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2S3_Init();
  MX_USART2_UART_Init();

  /* USER CODE BEGIN 2 */
  
  modify_i2s_pll(); // for F411
  
// init. SPDIF TX buffer for 1 block, fs=48 kHz, copy permitted, no built-in wave
  setup_spdif_txbuf(1, CH_STATUS_BITS, 0); 
  spdif_txind.room = 0; // assume buffer full at first
// start I2S transmission by DMA (automatic repeat by 'circular mode')  
  HAL_I2S_Transmit_DMA(&hSPDIF,      // handle of SPI/I2S for S/PDIF
                       spdif_txbuf,  // TX buffer (array of uint16_t)
                       SPDIF_TXBUF_INDMAX); // buffer size in 16-bit halfword
// Note: I2S configured for 16-bit data word / 16-bit frame per channel

  /* USER CODE END 2 */

  /* USER CODE BEGIN 3 */
  /* Infinite loop */
  while (1)
  {
// sin_cos_freq = 48   [kHz] * 3775 / (2 * pi * 2^16) = 440.05 [Hz]
// sin_cos_freq = 44.1 [kHz] * 4108 / (2 * pi * 2^16) = 439.96 [Hz]
    const uint16_t acc_mul[2] = {3775, 4108};
    const uint32_t acc_shift = 16;

    if (HAS_SPDIF_TXBUF_ROOM) {
      IDLE_LED_OFF; // show busy
      spdif_encode_subframe_data(sfbuf, 2); // put 2 subframes (L-ch/R-ch)
// update sin/cos value using DDA calculation
      cos_acc -= ((sin_acc * acc_mul[0]) >> acc_shift);
      sin_acc += ((cos_acc * acc_mul[0]) >> acc_shift);
      sfbuf[0] = cos_acc; // L-ch
      sfbuf[1] = sin_acc; // R-ch
    } else { // no room in SPDIF TX buffer
      IDLE_LED_ON; // show idle
    } // if (...
  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  __PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 5;
  RCC_OscInitStruct.PLL.PLLN = 210;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);

  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
  PeriphClkInitStruct.PLLI2S.PLLI2SN = 192;
  PeriphClkInitStruct.PLLI2S.PLLI2SR = 5;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

}

/* I2S3 init function */
void MX_I2S3_Init(void)
{

  hi2s3.Instance = SPI3;
  hi2s3.Init.Mode = I2S_MODE_MASTER_TX;
  hi2s3.Init.Standard = I2S_STANDARD_LSB;
  hi2s3.Init.DataFormat = I2S_DATAFORMAT_16B;
  hi2s3.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
#if defined(DAC_TEST)  
  hi2s3.Init.AudioFreq = I2S_AUDIOFREQ_48K;
#else  
  hi2s3.Init.AudioFreq = I2S_AUDIOFREQ_192K;
#endif  
  hi2s3.Init.CPOL = I2S_CPOL_LOW;
  hi2s3.Init.ClockSource = I2S_CLOCK_PLL;
  hi2s3.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE;
  HAL_I2S_Init(&hi2s3);

}

/* USART2 init function */
void MX_USART2_UART_Init(void)
{

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&huart2);

}

/** 
  * Enable DMA controller clock
  */
void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* Sets the priority grouping field */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
  HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __GPIOC_CLK_ENABLE();
  __GPIOH_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();
  __GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : PC13 */
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PA5 */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */

}

#endif

/**
  * @}
  */ 

/**
  * @}
*/ 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/