もっと今更、SC-88ProにS/PDIFを付けよう

Dependencies:   mbed

もっと今更、SC-88ProにS/PDIFを付けよう

STM32F103C8T6 ARM STM32 (blue pill)

  • モデル:STM32F103C8T6
  • コア:ARM 32 Cortex-M3 CPU
  • 72MHz頻度を作動させる
  • 64Kフラッシュメモリ、20K SRAM
  • 2.0-3.6Vパワー、I/O

というやつ。

/media/uploads/peu605/frontview.jpg

詳細はwikiの説明に

https://developer.mbed.org/users/peu605/code/DIT88proSTM32F1/wiki/説明

しまったなぁ、wikiのタイトル、漢字にしてしまったよ…

STM32F103C8T6, Roland, SC-88pro, S/PDIF, SPIDF, デジタル出力

Revision:
2:62c8aa0c38c7
Parent:
1:d7c7d1651f2e
Child:
3:bdac1803f0fd
--- a/main.cpp	Sat Sep 02 14:49:27 2017 +0000
+++ b/main.cpp	Mon Sep 04 16:54:24 2017 +0000
@@ -1,5 +1,6 @@
 #include "dit88prostm32.h"
-//#include "mbed.h"
+#include "mbed.h"
+
 
 /**
  * STM32F103C8T6 Blue Pill, Low Layer drivers test
@@ -32,11 +33,11 @@
 // serial audio data length
 #define SDATA_LENGH     18
 
-#define MAX_SPI_DELAY   12  // 32 - 19 - 1
-#define MASK31_19       0xfff80000
+#define MAX_SPI_DELAY   13  // 32 - 18 -1
+#define MASK31_20       0xfff00000
+#define MASK23_0        0x00ffffff
 
-#define _LED_LOAD
-//#define _LED_SPI_DELAY
+//#define _DEBUG_CONSOLE
 
 
 // SPI-DMA buffers
@@ -70,10 +71,11 @@
 
 int main()
 {
-
+    SystemClock_Config();
+    
     setupPeripherals();
     setChannelStatus();
-
+    
     HAL_Delay(1000);
 
     // enable SPI and deselect
@@ -93,15 +95,8 @@
     // wait for interrupt
     while (true) {
 
-#ifdef _LED_SPI_DELAY
-        // measured spiDelay is 3.
-        for (uint32_t i = 0; i < spiDelay; ++i) {
-            _LED_ON();
-            HAL_Delay(250);
-            _LED_OFF();
-            HAL_Delay(250);
-        }
-        HAL_Delay(1000);
+#ifdef _DEBUG_CONSOLE
+        debugOut();
 #endif
         __WFI();
 
@@ -112,18 +107,15 @@
 void transferFrames()
 {
     
-#ifdef _LED_LOAD
     // measured load is 20.8%
     _LED_OFF(); // PC_13 to HIGH
-#endif
     
     for (uint32_t i = 0; i < BUFFER_NUM_FRAMES / 2; ++i) {
         transferFrame();
     }
     
-#ifdef _LED_LOAD
     _LED_ON();  // PC_13 to LOW
-#endif
+    
 }
 
 
@@ -166,30 +158,32 @@
     // ======================================
     
     // Roland SC-88pro, 256fs, 18bit right justified, MSB first
-    // SC-88pro's output format might be 2's complement 18 bit audio data in 19 bit data frame.
+    // SC-88pro's output format seems to be 2's complement 18 bit audio data in 20 bit data frame.
     //
     // SPIRxBuff, each channel data have 128(=256/2) bits, M:MSB, L:LSB
+    // 127 <---                                      ---> 0
+    // 0000 ... 0000000  00000000000M====  ===============L
+    // 1111 ... 1111111  11111111111M====  ===============L
+    // ---- ... -------  ----------------  ----------------
     // +0 -> 5 hlf_word  +6                +7
-    // 0000 ... 0000000  0000000000000MM=  ===============L
-    // 1111 ... 1111111  1111111111111MM=  ===============L
-    // ---- ... -------  ----------------  ----------------
     // 1111 ... 0000000  1111110000000000  1111110000000000
     // 5432     6543210  5432109876543210  5432109876543210
     //
     // Actually, SPI starts some SCKs after LRCK change.
     // Received data are shifted leftward.
     //
-    // +0 -> 5 hlf_word  +6                +7         |<->| spiDelay
-    //                           MM======  ==========L
+    // 127 <---                                      ---> 0
+    //                                                |<->| spiDelay
+    //                         M=========  ==========L
     // ---- ... -------  ----------------  ----------------
+    // +0 -> 5 hlf_word  +6                +7
     // 1111 ... 0000000  1111110000000000  1111110000000000
     // 5432     6543210  5432109876543210  5432109876543210
     //
-    // bit[127:19] is all 0 or all 1.
+    // bit[127:20] is all 0 or all 1.
     //
-    // bit[31:19] should be 000...00 or 111...11
-    // bit[18] same as MSB bit
-    // bit[17:0] audio data, MSB to LSB
+    // bit[31:20] should be 000...00 or 111...11
+    // bit[19:0] MSB to LSB, 2's complement 18 bit audio data in 20 bit data frame
     
     // arithmetic right shift
     int32_t val = (*(rxBuffPtr + 6) << 16) | *(rxBuffPtr + 7);
@@ -197,8 +191,8 @@
     
     // determine spiDelay
     while(true) {
-        int32_t test = val & MASK31_19;
-        if (test == 0 || test ==  MASK31_19) {
+        int32_t test = val & MASK31_20;
+        if (test == 0 || test ==  MASK31_20) {
             break;
         } else {
             if (spiDelay == MAX_SPI_DELAY) {
@@ -221,7 +215,7 @@
     // So, V position is (28 - 4), C pos is (30 - 4), and P pos is (31 - 4).
     
     // mask with 24 bit to clear VUCP bits
-    val &= 0x00ffffff;
+    val &= MASK23_0;
 
     // set Channel status bit
     uint32_t bitPos = frameIndex & 7;
@@ -244,7 +238,7 @@
 
     // Z:preamble, A:aux, L:LSB, M:MSB, 0:filler(unused bit)
     // V:validity, U:user, C:ch status, P:parity
-    //                               ===> LSB to MSB, right to left
+    //                               ===> BMC encode from LSB to MSB
     //(PCUVM================L00AAAAZZZZ)
     //     PCUVM================L00AAAA  w/o preamble (= val)
     // --------------------------------
@@ -254,14 +248,14 @@
     // Write Biphase Mark Code data to SPITx-DMA buffer
     // First, 0 ~ 4 bit is Preamble. Not BMC!
     uint16_t bmc;
-    if (frameIndex == 0 && aCh) {
+    if (!aCh) {
+        bmc = lastCellZero ? PREAMBLE_Y : ~PREAMBLE_Y;
+    } else if (frameIndex == 0) {
         bmc = lastCellZero ? PREAMBLE_Z : ~PREAMBLE_Z;
-    } else if (aCh) {
+    } else {
         bmc = lastCellZero ? PREAMBLE_X : ~PREAMBLE_X;
-    } else {
-        bmc = lastCellZero ? PREAMBLE_Y : ~PREAMBLE_Y;
     }
-    lastCellZero = (bmc & 1) == 0;
+    lastCellZero = !(bmc & 1);  //lastCellZero = (bmc & 1) == 0;
     *txBuffPtr++ = bmc;
 
     // Next, 5 ~ 31 bit, audio data and VUCP bits. 28/4 = 7 loops
@@ -269,7 +263,7 @@
     for (uint32_t i = 0; i < 7 ; ++i) {
         bmc = lastCellZero
               ? bmcTable[val & 0x0f] : ~bmcTable[val & 0x0f];
-        lastCellZero = (bmc & 1) == 0;
+        lastCellZero = !(bmc & 1);
         *txBuffPtr++ = bmc;
         val >>= 4;
     }
@@ -339,8 +333,98 @@
 }
 
 
+void toBinary(uint16_t *val_ptr, char *str)
+{
+    uint16_t val = *val_ptr;
+    for (uint32_t j = 0; j < 16; ++j) {
+        *str = val & 0x8000 ? '1' : '0';
+        val <<= 1;
+        ++str;
+    }
+    *str = '\0';
+}
+
+#ifdef _DEBUG_CONSOLE
+uint16_t tmpData[8];
+char str[17];
+Serial pc(PA_2, PA_3);
+
+void debugOut()
+{
+//    pc.printf("SystemCoreClock =%d\n", SystemCoreClock);
+
+    for (uint8_t i = 6; i < 8; ++i) {
+        tmpData[i] = spiRxBuff[0].ltCh[i];
+    }
+    pc.printf("Delay:%02d", spiDelay);
+    for (uint8_t i = 6; i < 8; ++i) {
+        pc.printf(" ");
+        toBinary(&tmpData[i], (char*) &str);
+        pc.printf(str);
+    }
+    pc.printf("\n");
+    HAL_Delay(200);
+}
+#endif
+
+/**
+  * @brief  System Clock Configuration
+  *         The system Clock is configured as follow :
+  *            System Clock source            = PLL (HSE)
+  *            SYSCLK(Hz)                     = 72000000
+  *            HCLK(Hz)                       = 72000000
+  *            AHB Prescaler                  = 1
+  *            APB1 Prescaler                 = 2
+  *            APB2 Prescaler                 = 1
+  *            HSE Frequency(Hz)              = 8000000
+  *            PLLMUL                         = 9
+  *            Flash Latency(WS)              = 2
+  * @param  None
+  * @retval None
+  */
+void SystemClock_Config(void)
+{
+
+    /* Set FLASH latency */
+    LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
+
+    /* Enable HSE oscillator */
+//    LL_RCC_HSE_EnableBypass();
+    LL_RCC_HSE_Enable();
+    while(LL_RCC_HSE_IsReady() != 1) {
+    };
+
+    /* Main PLL configuration and activation */
+    LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE_DIV_1, LL_RCC_PLL_MUL_9);
+
+    LL_RCC_PLL_Enable();
+    while(LL_RCC_PLL_IsReady() != 1) {
+    };
+
+    /* Sysclk activation on the main PLL */
+    LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
+    LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
+    while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
+    };
+
+    /* Set APB1 & APB2 prescaler*/
+    LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
+    LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
+
+    /* Set systick to 1ms in using frequency set to 72MHz */
+    LL_Init1msTick(72000000);
+
+    /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
+    LL_SetSystemCoreClock(72000000);
+    
+    // 本当に72MHzかなぁ…
+
+}
+
+
 void setupPeripherals()
 {
+    
     // enable GPIOB/C clock
     LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
     LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
@@ -416,7 +500,4 @@
     LL_DMA_EnableChannel(_SPIRxDMA, _SPIRxDMACh);
     LL_DMA_EnableChannel(_SPITxDMA, _SPITxDMACh);
 
-    // sleep
-    LL_LPM_EnableSleep();
-
 }