もっと今更、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, デジタル出力

Committer:
peu605
Date:
Mon Sep 04 16:54:24 2017 +0000
Revision:
2:62c8aa0c38c7
Parent:
1:d7c7d1651f2e
Child:
3:bdac1803f0fd
??? 18bit length data in 20 bit frame.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
peu605 0:b3d998305b9d 1 #include "dit88prostm32.h"
peu605 2:62c8aa0c38c7 2 #include "mbed.h"
peu605 2:62c8aa0c38c7 3
peu605 0:b3d998305b9d 4
peu605 0:b3d998305b9d 5 /**
peu605 0:b3d998305b9d 6 * STM32F103C8T6 Blue Pill, Low Layer drivers test
peu605 0:b3d998305b9d 7 *
peu605 0:b3d998305b9d 8 * Software Digital audio Transmitter
peu605 0:b3d998305b9d 9 * for Roland SC-88pro (32kHz, 18bit, Right justified, 256fs)
peu605 0:b3d998305b9d 10 *
peu605 0:b3d998305b9d 11 * @author masuda, Masuda Naika
peu605 0:b3d998305b9d 12 */
peu605 0:b3d998305b9d 13
peu605 0:b3d998305b9d 14 #define _SPI SPI2
peu605 0:b3d998305b9d 15 #define _SPIRxDMA DMA1
peu605 0:b3d998305b9d 16 #define _SPIRxDMACh LL_DMA_CHANNEL_4
peu605 0:b3d998305b9d 17 #define _SPIRxDMAIRQn DMA1_Channel4_IRQn
peu605 0:b3d998305b9d 18 #define _SPITxDMA DMA1
peu605 0:b3d998305b9d 19 #define _SPITxDMACh LL_DMA_CHANNEL_5
peu605 0:b3d998305b9d 20
peu605 0:b3d998305b9d 21 #define _SPI_NSS_SOFTWARE() _SPI->CR1 |= SPI_CR1_SSM // NSS softare management
peu605 0:b3d998305b9d 22 #define _SPI_DESELECT_SLAVE() _SPI->CR1 |= SPI_CR1_SSI // deselect slave
peu605 0:b3d998305b9d 23 #define _SPI_SELECT_SLAVE() _SPI->CR1 &= ~SPI_CR1_SSI // select slave
peu605 0:b3d998305b9d 24 #define _SPI_ENABLE() _SPI->CR1 |= SPI_CR1_SPE // SPI enable
peu605 0:b3d998305b9d 25 #define _SPI_DISABLE() _SPI->CR1 &= ~SPI_CR1_SPE // SPI disable
peu605 0:b3d998305b9d 26
peu605 0:b3d998305b9d 27 #define _LED_ON() LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_13)
peu605 0:b3d998305b9d 28 #define _LED_OFF() LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_13)
peu605 0:b3d998305b9d 29
peu605 0:b3d998305b9d 30 #define BUFFER_NUM_FRAMES 4 // LR|LR/LR|LR, IRQ freq is 16kHz
peu605 0:b3d998305b9d 31 #define DMA_TRANSFER_LENGTH (8 * 2 * BUFFER_NUM_FRAMES)
peu605 0:b3d998305b9d 32
peu605 0:b3d998305b9d 33 // serial audio data length
peu605 0:b3d998305b9d 34 #define SDATA_LENGH 18
peu605 0:b3d998305b9d 35
peu605 2:62c8aa0c38c7 36 #define MAX_SPI_DELAY 13 // 32 - 18 -1
peu605 2:62c8aa0c38c7 37 #define MASK31_20 0xfff00000
peu605 2:62c8aa0c38c7 38 #define MASK23_0 0x00ffffff
peu605 0:b3d998305b9d 39
peu605 2:62c8aa0c38c7 40 //#define _DEBUG_CONSOLE
peu605 0:b3d998305b9d 41
peu605 0:b3d998305b9d 42
peu605 0:b3d998305b9d 43 // SPI-DMA buffers
peu605 0:b3d998305b9d 44 volatile SpiRxBuff spiRxBuff[BUFFER_NUM_FRAMES];
peu605 0:b3d998305b9d 45 volatile SpiTxBuff spiTxBuff[BUFFER_NUM_FRAMES];
peu605 0:b3d998305b9d 46
peu605 0:b3d998305b9d 47 // channel status table
peu605 0:b3d998305b9d 48 volatile ChannelStatus channelStatus[24];
peu605 0:b3d998305b9d 49
peu605 0:b3d998305b9d 50 // SPI bit delay
peu605 0:b3d998305b9d 51 volatile uint32_t spiDelay = 0;
peu605 0:b3d998305b9d 52
peu605 0:b3d998305b9d 53
peu605 0:b3d998305b9d 54 extern "C" void DMA1_Channel4_IRQHandler(void)
peu605 0:b3d998305b9d 55 {
peu605 0:b3d998305b9d 56
peu605 0:b3d998305b9d 57 // SPI Rx DMA
peu605 0:b3d998305b9d 58 if(LL_DMA_IsActiveFlag_HT4(_SPIRxDMA)) {
peu605 0:b3d998305b9d 59 // half transfer
peu605 0:b3d998305b9d 60 LL_DMA_ClearFlag_HT4(_SPIRxDMA);
peu605 0:b3d998305b9d 61 transferFrames();
peu605 0:b3d998305b9d 62
peu605 0:b3d998305b9d 63 } else if (LL_DMA_IsActiveFlag_TC4(_SPIRxDMA)) {
peu605 0:b3d998305b9d 64 // transfer complete
peu605 0:b3d998305b9d 65 LL_DMA_ClearFlag_TC4(_SPIRxDMA);
peu605 0:b3d998305b9d 66 transferFrames();
peu605 0:b3d998305b9d 67 }
peu605 0:b3d998305b9d 68
peu605 0:b3d998305b9d 69 }
peu605 0:b3d998305b9d 70
peu605 0:b3d998305b9d 71
peu605 0:b3d998305b9d 72 int main()
peu605 0:b3d998305b9d 73 {
peu605 2:62c8aa0c38c7 74 SystemClock_Config();
peu605 2:62c8aa0c38c7 75
peu605 0:b3d998305b9d 76 setupPeripherals();
peu605 0:b3d998305b9d 77 setChannelStatus();
peu605 2:62c8aa0c38c7 78
peu605 0:b3d998305b9d 79 HAL_Delay(1000);
peu605 0:b3d998305b9d 80
peu605 0:b3d998305b9d 81 // enable SPI and deselect
peu605 0:b3d998305b9d 82 _SPI_DESELECT_SLAVE();
peu605 0:b3d998305b9d 83 _SPI_ENABLE(); // LL_SPI_Enable(_SPI);
peu605 0:b3d998305b9d 84
peu605 0:b3d998305b9d 85 uint16_t spiCR1 = _SPI->CR1 & ~SPI_CR1_SSI; // use pre calculated value
peu605 0:b3d998305b9d 86
peu605 0:b3d998305b9d 87 // LRCK Hi = Left channel
peu605 0:b3d998305b9d 88 // Wait LRCK rise and start SPI as soon as possible
peu605 0:b3d998305b9d 89 while(LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_12) != 0); // wait for falling edge
peu605 0:b3d998305b9d 90 while(LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_12) == 0); // wait for rising edge
peu605 0:b3d998305b9d 91
peu605 0:b3d998305b9d 92 // select slave
peu605 0:b3d998305b9d 93 _SPI->CR1 = spiCR1;
peu605 0:b3d998305b9d 94
peu605 0:b3d998305b9d 95 // wait for interrupt
peu605 0:b3d998305b9d 96 while (true) {
peu605 0:b3d998305b9d 97
peu605 2:62c8aa0c38c7 98 #ifdef _DEBUG_CONSOLE
peu605 2:62c8aa0c38c7 99 debugOut();
peu605 0:b3d998305b9d 100 #endif
peu605 0:b3d998305b9d 101 __WFI();
peu605 0:b3d998305b9d 102
peu605 0:b3d998305b9d 103 }
peu605 0:b3d998305b9d 104 }
peu605 0:b3d998305b9d 105
peu605 0:b3d998305b9d 106
peu605 0:b3d998305b9d 107 void transferFrames()
peu605 0:b3d998305b9d 108 {
peu605 0:b3d998305b9d 109
peu605 0:b3d998305b9d 110 // measured load is 20.8%
peu605 0:b3d998305b9d 111 _LED_OFF(); // PC_13 to HIGH
peu605 0:b3d998305b9d 112
peu605 0:b3d998305b9d 113 for (uint32_t i = 0; i < BUFFER_NUM_FRAMES / 2; ++i) {
peu605 0:b3d998305b9d 114 transferFrame();
peu605 0:b3d998305b9d 115 }
peu605 0:b3d998305b9d 116
peu605 0:b3d998305b9d 117 _LED_ON(); // PC_13 to LOW
peu605 2:62c8aa0c38c7 118
peu605 0:b3d998305b9d 119 }
peu605 0:b3d998305b9d 120
peu605 0:b3d998305b9d 121
peu605 0:b3d998305b9d 122 void transferFrame()
peu605 0:b3d998305b9d 123 {
peu605 0:b3d998305b9d 124
peu605 0:b3d998305b9d 125 static uint32_t frameIndex = 0;
peu605 0:b3d998305b9d 126 static uint32_t buffIndex = 0;
peu605 0:b3d998305b9d 127
peu605 0:b3d998305b9d 128 uint16_t *rxBuffPtr, *txBuffPtr;
peu605 0:b3d998305b9d 129
peu605 0:b3d998305b9d 130 // transfer left channel
peu605 0:b3d998305b9d 131 rxBuffPtr = (uint16_t*) &spiRxBuff[buffIndex].ltCh;
peu605 0:b3d998305b9d 132 txBuffPtr = (uint16_t*) &spiTxBuff[buffIndex].aCh;
peu605 0:b3d998305b9d 133 transferSubFrame(frameIndex, true, rxBuffPtr, txBuffPtr);
peu605 0:b3d998305b9d 134
peu605 0:b3d998305b9d 135 // transfer right channel
peu605 0:b3d998305b9d 136 rxBuffPtr = (uint16_t*) &spiRxBuff[buffIndex].rtCh;
peu605 0:b3d998305b9d 137 txBuffPtr = (uint16_t*) &spiTxBuff[buffIndex].bCh;
peu605 0:b3d998305b9d 138 transferSubFrame(frameIndex, false, rxBuffPtr, txBuffPtr);
peu605 0:b3d998305b9d 139
peu605 0:b3d998305b9d 140 if (++frameIndex == 192) {
peu605 0:b3d998305b9d 141 frameIndex = 0;
peu605 0:b3d998305b9d 142 }
peu605 0:b3d998305b9d 143 if (++buffIndex == BUFFER_NUM_FRAMES) {
peu605 0:b3d998305b9d 144 buffIndex = 0;
peu605 0:b3d998305b9d 145 }
peu605 0:b3d998305b9d 146
peu605 0:b3d998305b9d 147 }
peu605 0:b3d998305b9d 148
peu605 0:b3d998305b9d 149
peu605 0:b3d998305b9d 150 void transferSubFrame(uint32_t frameIndex, bool aCh, uint16_t *rxBuffPtr, uint16_t *txBuffPtr)
peu605 0:b3d998305b9d 151 {
peu605 0:b3d998305b9d 152
peu605 0:b3d998305b9d 153 static bool lastCellZero = true;
peu605 0:b3d998305b9d 154 // static uint32_t spiDelay = 0;
peu605 0:b3d998305b9d 155
peu605 0:b3d998305b9d 156 // ======================================
peu605 0:b3d998305b9d 157 // Read rx buffer and make raw SPIDF data
peu605 0:b3d998305b9d 158 // ======================================
peu605 0:b3d998305b9d 159
peu605 0:b3d998305b9d 160 // Roland SC-88pro, 256fs, 18bit right justified, MSB first
peu605 2:62c8aa0c38c7 161 // SC-88pro's output format seems to be 2's complement 18 bit audio data in 20 bit data frame.
peu605 0:b3d998305b9d 162 //
peu605 0:b3d998305b9d 163 // SPIRxBuff, each channel data have 128(=256/2) bits, M:MSB, L:LSB
peu605 2:62c8aa0c38c7 164 // 127 <--- ---> 0
peu605 2:62c8aa0c38c7 165 // 0000 ... 0000000 00000000000M==== ===============L
peu605 2:62c8aa0c38c7 166 // 1111 ... 1111111 11111111111M==== ===============L
peu605 2:62c8aa0c38c7 167 // ---- ... ------- ---------------- ----------------
peu605 0:b3d998305b9d 168 // +0 -> 5 hlf_word +6 +7
peu605 0:b3d998305b9d 169 // 1111 ... 0000000 1111110000000000 1111110000000000
peu605 0:b3d998305b9d 170 // 5432 6543210 5432109876543210 5432109876543210
peu605 0:b3d998305b9d 171 //
peu605 0:b3d998305b9d 172 // Actually, SPI starts some SCKs after LRCK change.
peu605 0:b3d998305b9d 173 // Received data are shifted leftward.
peu605 0:b3d998305b9d 174 //
peu605 2:62c8aa0c38c7 175 // 127 <--- ---> 0
peu605 2:62c8aa0c38c7 176 // |<->| spiDelay
peu605 2:62c8aa0c38c7 177 // M========= ==========L
peu605 0:b3d998305b9d 178 // ---- ... ------- ---------------- ----------------
peu605 2:62c8aa0c38c7 179 // +0 -> 5 hlf_word +6 +7
peu605 0:b3d998305b9d 180 // 1111 ... 0000000 1111110000000000 1111110000000000
peu605 0:b3d998305b9d 181 // 5432 6543210 5432109876543210 5432109876543210
peu605 0:b3d998305b9d 182 //
peu605 2:62c8aa0c38c7 183 // bit[127:20] is all 0 or all 1.
peu605 0:b3d998305b9d 184 //
peu605 2:62c8aa0c38c7 185 // bit[31:20] should be 000...00 or 111...11
peu605 2:62c8aa0c38c7 186 // bit[19:0] MSB to LSB, 2's complement 18 bit audio data in 20 bit data frame
peu605 0:b3d998305b9d 187
peu605 0:b3d998305b9d 188 // arithmetic right shift
peu605 0:b3d998305b9d 189 int32_t val = (*(rxBuffPtr + 6) << 16) | *(rxBuffPtr + 7);
peu605 0:b3d998305b9d 190 val >>= spiDelay;
peu605 0:b3d998305b9d 191
peu605 0:b3d998305b9d 192 // determine spiDelay
peu605 0:b3d998305b9d 193 while(true) {
peu605 2:62c8aa0c38c7 194 int32_t test = val & MASK31_20;
peu605 2:62c8aa0c38c7 195 if (test == 0 || test == MASK31_20) {
peu605 0:b3d998305b9d 196 break;
peu605 0:b3d998305b9d 197 } else {
peu605 0:b3d998305b9d 198 if (spiDelay == MAX_SPI_DELAY) {
peu605 0:b3d998305b9d 199 spiDelay = 0;
peu605 0:b3d998305b9d 200 val = 0; // discard data
peu605 0:b3d998305b9d 201 break;
peu605 0:b3d998305b9d 202 } else {
peu605 0:b3d998305b9d 203 ++spiDelay;
peu605 0:b3d998305b9d 204 val >>= 1;
peu605 0:b3d998305b9d 205 }
peu605 0:b3d998305b9d 206 }
peu605 0:b3d998305b9d 207 }
peu605 0:b3d998305b9d 208
peu605 0:b3d998305b9d 209 // left shift to fit 24 bit width
peu605 0:b3d998305b9d 210 val <<= (24 - SDATA_LENGH);
peu605 0:b3d998305b9d 211
peu605 0:b3d998305b9d 212 // 4-27 data, 28 V, 29 U, 30 C, 31 P
peu605 0:b3d998305b9d 213 // U = 0
peu605 0:b3d998305b9d 214 // 'val' here does not have preamble.
peu605 0:b3d998305b9d 215 // So, V position is (28 - 4), C pos is (30 - 4), and P pos is (31 - 4).
peu605 0:b3d998305b9d 216
peu605 0:b3d998305b9d 217 // mask with 24 bit to clear VUCP bits
peu605 2:62c8aa0c38c7 218 val &= MASK23_0;
peu605 0:b3d998305b9d 219
peu605 0:b3d998305b9d 220 // set Channel status bit
peu605 0:b3d998305b9d 221 uint32_t bitPos = frameIndex & 7;
peu605 0:b3d998305b9d 222 uint32_t offset = frameIndex >> 3;
peu605 0:b3d998305b9d 223 uint8_t *chStatusPtr = aCh
peu605 0:b3d998305b9d 224 ? (uint8_t*) &channelStatus[offset].ltCh
peu605 0:b3d998305b9d 225 : (uint8_t*) &channelStatus[offset].rtCh;
peu605 0:b3d998305b9d 226 if (*chStatusPtr & _BV(bitPos)) {
peu605 0:b3d998305b9d 227 val |= _BV(30 - 4);
peu605 0:b3d998305b9d 228 }
peu605 0:b3d998305b9d 229
peu605 0:b3d998305b9d 230 // set parity bit
peu605 0:b3d998305b9d 231 if (oddParity(val)) {
peu605 0:b3d998305b9d 232 val |= _BV(31 - 4);
peu605 0:b3d998305b9d 233 }
peu605 0:b3d998305b9d 234
peu605 1:d7c7d1651f2e 235 // ===============================================
peu605 1:d7c7d1651f2e 236 // Biphase Mark Code encode and write to Tx buffer
peu605 1:d7c7d1651f2e 237 // ===============================================
peu605 0:b3d998305b9d 238
peu605 0:b3d998305b9d 239 // Z:preamble, A:aux, L:LSB, M:MSB, 0:filler(unused bit)
peu605 0:b3d998305b9d 240 // V:validity, U:user, C:ch status, P:parity
peu605 2:62c8aa0c38c7 241 // ===> BMC encode from LSB to MSB
peu605 0:b3d998305b9d 242 //(PCUVM================L00AAAAZZZZ)
peu605 0:b3d998305b9d 243 // PCUVM================L00AAAA w/o preamble (= val)
peu605 0:b3d998305b9d 244 // --------------------------------
peu605 0:b3d998305b9d 245 // 33222222222211111111110000000000
peu605 0:b3d998305b9d 246 // 10987654321098765432109876543210
peu605 0:b3d998305b9d 247
peu605 0:b3d998305b9d 248 // Write Biphase Mark Code data to SPITx-DMA buffer
peu605 0:b3d998305b9d 249 // First, 0 ~ 4 bit is Preamble. Not BMC!
peu605 0:b3d998305b9d 250 uint16_t bmc;
peu605 2:62c8aa0c38c7 251 if (!aCh) {
peu605 2:62c8aa0c38c7 252 bmc = lastCellZero ? PREAMBLE_Y : ~PREAMBLE_Y;
peu605 2:62c8aa0c38c7 253 } else if (frameIndex == 0) {
peu605 0:b3d998305b9d 254 bmc = lastCellZero ? PREAMBLE_Z : ~PREAMBLE_Z;
peu605 2:62c8aa0c38c7 255 } else {
peu605 0:b3d998305b9d 256 bmc = lastCellZero ? PREAMBLE_X : ~PREAMBLE_X;
peu605 0:b3d998305b9d 257 }
peu605 2:62c8aa0c38c7 258 lastCellZero = !(bmc & 1); //lastCellZero = (bmc & 1) == 0;
peu605 0:b3d998305b9d 259 *txBuffPtr++ = bmc;
peu605 0:b3d998305b9d 260
peu605 1:d7c7d1651f2e 261 // Next, 5 ~ 31 bit, audio data and VUCP bits. 28/4 = 7 loops
peu605 0:b3d998305b9d 262 // BMC encode each by lower 4 bits
peu605 0:b3d998305b9d 263 for (uint32_t i = 0; i < 7 ; ++i) {
peu605 0:b3d998305b9d 264 bmc = lastCellZero
peu605 0:b3d998305b9d 265 ? bmcTable[val & 0x0f] : ~bmcTable[val & 0x0f];
peu605 2:62c8aa0c38c7 266 lastCellZero = !(bmc & 1);
peu605 0:b3d998305b9d 267 *txBuffPtr++ = bmc;
peu605 0:b3d998305b9d 268 val >>= 4;
peu605 0:b3d998305b9d 269 }
peu605 0:b3d998305b9d 270
peu605 0:b3d998305b9d 271 }
peu605 0:b3d998305b9d 272
peu605 0:b3d998305b9d 273
peu605 0:b3d998305b9d 274 // consumer, copy allowed, 18bit, 32kHz
peu605 0:b3d998305b9d 275 void setChannelStatus()
peu605 0:b3d998305b9d 276 {
peu605 0:b3d998305b9d 277
peu605 0:b3d998305b9d 278 // Byte 0: General control and mode information
peu605 0:b3d998305b9d 279 // copy enable
peu605 0:b3d998305b9d 280 channelStatus[0].ltCh = _BV(C_COPY);
peu605 0:b3d998305b9d 281 channelStatus[0].rtCh = _BV(C_COPY);
peu605 0:b3d998305b9d 282
peu605 0:b3d998305b9d 283 // Byte 1: Category code
peu605 0:b3d998305b9d 284 // general
peu605 0:b3d998305b9d 285 channelStatus[1].ltCh = 0;
peu605 0:b3d998305b9d 286 channelStatus[1].rtCh = 0;
peu605 0:b3d998305b9d 287
peu605 0:b3d998305b9d 288 // Byte 2: Source and channel number
peu605 0:b3d998305b9d 289 channelStatus[2].ltCh = 0b0001 << 4;
peu605 0:b3d998305b9d 290 channelStatus[2].rtCh = 0b0010 << 4;
peu605 0:b3d998305b9d 291
peu605 0:b3d998305b9d 292 // Byte 3: Sampling frequency and clock accuracy
peu605 0:b3d998305b9d 293 channelStatus[3].ltCh = _BV(C_FS1) | _BV(C_FS0);
peu605 0:b3d998305b9d 294 channelStatus[3].rtCh = _BV(C_FS1) | _BV(C_FS0);
peu605 0:b3d998305b9d 295
peu605 0:b3d998305b9d 296 // Byte 23: CRC
peu605 0:b3d998305b9d 297 uint8_t *chStatusPtr = (uint8_t*) channelStatus;
peu605 0:b3d998305b9d 298 channelStatus[23].ltCh = calcCRC(chStatusPtr);
peu605 0:b3d998305b9d 299 ++chStatusPtr;
peu605 0:b3d998305b9d 300 channelStatus[23].rtCh = calcCRC(chStatusPtr);
peu605 0:b3d998305b9d 301
peu605 0:b3d998305b9d 302 }
peu605 0:b3d998305b9d 303
peu605 0:b3d998305b9d 304
peu605 0:b3d998305b9d 305 uint32_t oddParity(uint32_t val)
peu605 0:b3d998305b9d 306 {
peu605 0:b3d998305b9d 307 val ^= val >> 16;
peu605 0:b3d998305b9d 308 val ^= val >> 8;
peu605 0:b3d998305b9d 309 val ^= val >> 4;
peu605 0:b3d998305b9d 310 val ^= val >> 2;
peu605 0:b3d998305b9d 311 val ^= val >> 1;
peu605 0:b3d998305b9d 312 return val & 1;
peu605 0:b3d998305b9d 313 }
peu605 0:b3d998305b9d 314
peu605 0:b3d998305b9d 315
peu605 0:b3d998305b9d 316 uint8_t calcCRC(uint8_t *chStatusPtr)
peu605 0:b3d998305b9d 317 {
peu605 0:b3d998305b9d 318 uint8_t crc = 255;
peu605 0:b3d998305b9d 319 for (uint32_t i = 0; i < 24; ++i) {
peu605 0:b3d998305b9d 320 uint8_t b = *chStatusPtr;
peu605 0:b3d998305b9d 321 for (uint32_t j = 0; j < 8; ++j) {
peu605 0:b3d998305b9d 322 if ((crc & 1) ^ (b & 1)) {
peu605 0:b3d998305b9d 323 crc >>= 1;
peu605 0:b3d998305b9d 324 crc ^= 0xb8;
peu605 0:b3d998305b9d 325 } else {
peu605 0:b3d998305b9d 326 crc >>= 1;
peu605 0:b3d998305b9d 327 }
peu605 0:b3d998305b9d 328 b >>= 1;
peu605 0:b3d998305b9d 329 }
peu605 0:b3d998305b9d 330 chStatusPtr += 2;
peu605 0:b3d998305b9d 331 }
peu605 0:b3d998305b9d 332 return crc;
peu605 0:b3d998305b9d 333 }
peu605 0:b3d998305b9d 334
peu605 0:b3d998305b9d 335
peu605 2:62c8aa0c38c7 336 void toBinary(uint16_t *val_ptr, char *str)
peu605 2:62c8aa0c38c7 337 {
peu605 2:62c8aa0c38c7 338 uint16_t val = *val_ptr;
peu605 2:62c8aa0c38c7 339 for (uint32_t j = 0; j < 16; ++j) {
peu605 2:62c8aa0c38c7 340 *str = val & 0x8000 ? '1' : '0';
peu605 2:62c8aa0c38c7 341 val <<= 1;
peu605 2:62c8aa0c38c7 342 ++str;
peu605 2:62c8aa0c38c7 343 }
peu605 2:62c8aa0c38c7 344 *str = '\0';
peu605 2:62c8aa0c38c7 345 }
peu605 2:62c8aa0c38c7 346
peu605 2:62c8aa0c38c7 347 #ifdef _DEBUG_CONSOLE
peu605 2:62c8aa0c38c7 348 uint16_t tmpData[8];
peu605 2:62c8aa0c38c7 349 char str[17];
peu605 2:62c8aa0c38c7 350 Serial pc(PA_2, PA_3);
peu605 2:62c8aa0c38c7 351
peu605 2:62c8aa0c38c7 352 void debugOut()
peu605 2:62c8aa0c38c7 353 {
peu605 2:62c8aa0c38c7 354 // pc.printf("SystemCoreClock =%d\n", SystemCoreClock);
peu605 2:62c8aa0c38c7 355
peu605 2:62c8aa0c38c7 356 for (uint8_t i = 6; i < 8; ++i) {
peu605 2:62c8aa0c38c7 357 tmpData[i] = spiRxBuff[0].ltCh[i];
peu605 2:62c8aa0c38c7 358 }
peu605 2:62c8aa0c38c7 359 pc.printf("Delay:%02d", spiDelay);
peu605 2:62c8aa0c38c7 360 for (uint8_t i = 6; i < 8; ++i) {
peu605 2:62c8aa0c38c7 361 pc.printf(" ");
peu605 2:62c8aa0c38c7 362 toBinary(&tmpData[i], (char*) &str);
peu605 2:62c8aa0c38c7 363 pc.printf(str);
peu605 2:62c8aa0c38c7 364 }
peu605 2:62c8aa0c38c7 365 pc.printf("\n");
peu605 2:62c8aa0c38c7 366 HAL_Delay(200);
peu605 2:62c8aa0c38c7 367 }
peu605 2:62c8aa0c38c7 368 #endif
peu605 2:62c8aa0c38c7 369
peu605 2:62c8aa0c38c7 370 /**
peu605 2:62c8aa0c38c7 371 * @brief System Clock Configuration
peu605 2:62c8aa0c38c7 372 * The system Clock is configured as follow :
peu605 2:62c8aa0c38c7 373 * System Clock source = PLL (HSE)
peu605 2:62c8aa0c38c7 374 * SYSCLK(Hz) = 72000000
peu605 2:62c8aa0c38c7 375 * HCLK(Hz) = 72000000
peu605 2:62c8aa0c38c7 376 * AHB Prescaler = 1
peu605 2:62c8aa0c38c7 377 * APB1 Prescaler = 2
peu605 2:62c8aa0c38c7 378 * APB2 Prescaler = 1
peu605 2:62c8aa0c38c7 379 * HSE Frequency(Hz) = 8000000
peu605 2:62c8aa0c38c7 380 * PLLMUL = 9
peu605 2:62c8aa0c38c7 381 * Flash Latency(WS) = 2
peu605 2:62c8aa0c38c7 382 * @param None
peu605 2:62c8aa0c38c7 383 * @retval None
peu605 2:62c8aa0c38c7 384 */
peu605 2:62c8aa0c38c7 385 void SystemClock_Config(void)
peu605 2:62c8aa0c38c7 386 {
peu605 2:62c8aa0c38c7 387
peu605 2:62c8aa0c38c7 388 /* Set FLASH latency */
peu605 2:62c8aa0c38c7 389 LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
peu605 2:62c8aa0c38c7 390
peu605 2:62c8aa0c38c7 391 /* Enable HSE oscillator */
peu605 2:62c8aa0c38c7 392 // LL_RCC_HSE_EnableBypass();
peu605 2:62c8aa0c38c7 393 LL_RCC_HSE_Enable();
peu605 2:62c8aa0c38c7 394 while(LL_RCC_HSE_IsReady() != 1) {
peu605 2:62c8aa0c38c7 395 };
peu605 2:62c8aa0c38c7 396
peu605 2:62c8aa0c38c7 397 /* Main PLL configuration and activation */
peu605 2:62c8aa0c38c7 398 LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE_DIV_1, LL_RCC_PLL_MUL_9);
peu605 2:62c8aa0c38c7 399
peu605 2:62c8aa0c38c7 400 LL_RCC_PLL_Enable();
peu605 2:62c8aa0c38c7 401 while(LL_RCC_PLL_IsReady() != 1) {
peu605 2:62c8aa0c38c7 402 };
peu605 2:62c8aa0c38c7 403
peu605 2:62c8aa0c38c7 404 /* Sysclk activation on the main PLL */
peu605 2:62c8aa0c38c7 405 LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
peu605 2:62c8aa0c38c7 406 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
peu605 2:62c8aa0c38c7 407 while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
peu605 2:62c8aa0c38c7 408 };
peu605 2:62c8aa0c38c7 409
peu605 2:62c8aa0c38c7 410 /* Set APB1 & APB2 prescaler*/
peu605 2:62c8aa0c38c7 411 LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
peu605 2:62c8aa0c38c7 412 LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
peu605 2:62c8aa0c38c7 413
peu605 2:62c8aa0c38c7 414 /* Set systick to 1ms in using frequency set to 72MHz */
peu605 2:62c8aa0c38c7 415 LL_Init1msTick(72000000);
peu605 2:62c8aa0c38c7 416
peu605 2:62c8aa0c38c7 417 /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
peu605 2:62c8aa0c38c7 418 LL_SetSystemCoreClock(72000000);
peu605 2:62c8aa0c38c7 419
peu605 2:62c8aa0c38c7 420 // 本当に72MHzかなぁ…
peu605 2:62c8aa0c38c7 421
peu605 2:62c8aa0c38c7 422 }
peu605 2:62c8aa0c38c7 423
peu605 2:62c8aa0c38c7 424
peu605 0:b3d998305b9d 425 void setupPeripherals()
peu605 0:b3d998305b9d 426 {
peu605 2:62c8aa0c38c7 427
peu605 0:b3d998305b9d 428 // enable GPIOB/C clock
peu605 0:b3d998305b9d 429 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
peu605 0:b3d998305b9d 430 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
peu605 0:b3d998305b9d 431
peu605 0:b3d998305b9d 432 // Configure GPIO pin : LED_Pin, PC13, OUTPUT
peu605 0:b3d998305b9d 433 LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_OUTPUT);
peu605 0:b3d998305b9d 434 LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_13, LL_GPIO_OUTPUT_PUSHPULL);
peu605 0:b3d998305b9d 435 LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 436
peu605 0:b3d998305b9d 437 // SPI IO pins
peu605 0:b3d998305b9d 438 // PB13 -> SCK, 5V tolerant
peu605 0:b3d998305b9d 439 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_13, LL_GPIO_MODE_ALTERNATE);
peu605 0:b3d998305b9d 440 LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_13, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 441 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 442 // PB14 -> MISO, 5V tolerant
peu605 0:b3d998305b9d 443 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_14, LL_GPIO_MODE_ALTERNATE);
peu605 0:b3d998305b9d 444 LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_14, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 445 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_14, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 446 // PB15 -> MOSI, 5V tolerant
peu605 0:b3d998305b9d 447 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_15, LL_GPIO_MODE_ALTERNATE);
peu605 0:b3d998305b9d 448 LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_15, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 449 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_15, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 450 // PB12 -> LRCK, 5V tolerant
peu605 0:b3d998305b9d 451 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_12, LL_GPIO_MODE_INPUT);
peu605 0:b3d998305b9d 452 // LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_12, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 453 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_12, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 454
peu605 0:b3d998305b9d 455 // SPI Slave full duplex, mode 0, 16bit
peu605 0:b3d998305b9d 456 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); // SPI2
peu605 0:b3d998305b9d 457 LL_SPI_SetMode(_SPI, LL_SPI_MODE_SLAVE);
peu605 0:b3d998305b9d 458 LL_SPI_SetTransferDirection(_SPI,LL_SPI_FULL_DUPLEX);
peu605 0:b3d998305b9d 459 LL_SPI_SetClockPhase(_SPI, LL_SPI_PHASE_1EDGE);
peu605 0:b3d998305b9d 460 LL_SPI_SetClockPolarity(_SPI, LL_SPI_POLARITY_LOW);
peu605 0:b3d998305b9d 461 LL_SPI_SetTransferBitOrder(_SPI, LL_SPI_MSB_FIRST);
peu605 0:b3d998305b9d 462 LL_SPI_SetDataWidth(_SPI, LL_SPI_DATAWIDTH_16BIT);
peu605 0:b3d998305b9d 463 LL_SPI_SetNSSMode(_SPI, LL_SPI_NSS_SOFT);
peu605 0:b3d998305b9d 464
peu605 0:b3d998305b9d 465 // connect to DMAReq
peu605 0:b3d998305b9d 466 LL_SPI_EnableDMAReq_RX(_SPI);
peu605 0:b3d998305b9d 467 LL_SPI_EnableDMAReq_TX(_SPI);
peu605 0:b3d998305b9d 468
peu605 0:b3d998305b9d 469
peu605 0:b3d998305b9d 470 // DMA
peu605 0:b3d998305b9d 471 LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); // DMA1
peu605 0:b3d998305b9d 472 // _SPIRxDMA, DMA1 Channel 4
peu605 0:b3d998305b9d 473 LL_DMA_ConfigTransfer(_SPIRxDMA, _SPIRxDMACh,
peu605 0:b3d998305b9d 474 LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_CIRCULAR |
peu605 0:b3d998305b9d 475 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
peu605 0:b3d998305b9d 476 LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD);
peu605 0:b3d998305b9d 477 LL_DMA_ConfigAddresses(_SPIRxDMA, _SPIRxDMACh,
peu605 0:b3d998305b9d 478 (uint32_t)&(_SPI->DR), (uint32_t)&spiRxBuff,
peu605 0:b3d998305b9d 479 LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
peu605 0:b3d998305b9d 480 LL_DMA_SetDataLength(_SPIRxDMA, _SPIRxDMACh, DMA_TRANSFER_LENGTH);
peu605 0:b3d998305b9d 481
peu605 0:b3d998305b9d 482 // _SPITxDMA, DMA1 Channel5
peu605 0:b3d998305b9d 483 LL_DMA_ConfigTransfer(_SPITxDMA, _SPITxDMACh,
peu605 0:b3d998305b9d 484 LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_MEDIUM | LL_DMA_MODE_CIRCULAR |
peu605 0:b3d998305b9d 485 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
peu605 0:b3d998305b9d 486 LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD);
peu605 0:b3d998305b9d 487 LL_DMA_ConfigAddresses(_SPITxDMA, _SPITxDMACh,
peu605 0:b3d998305b9d 488 (uint32_t)&spiTxBuff, (uint32_t)&(_SPI->DR),
peu605 0:b3d998305b9d 489 LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
peu605 0:b3d998305b9d 490 LL_DMA_SetDataLength(_SPITxDMA, _SPITxDMACh, DMA_TRANSFER_LENGTH);
peu605 0:b3d998305b9d 491
peu605 0:b3d998305b9d 492 // Enable SPIRx DMA IRQ, Half Transfer and Transfer Complete
peu605 0:b3d998305b9d 493 NVIC_SetPriority(_SPIRxDMAIRQn, 0);
peu605 0:b3d998305b9d 494 NVIC_EnableIRQ(_SPIRxDMAIRQn);
peu605 0:b3d998305b9d 495
peu605 0:b3d998305b9d 496 LL_DMA_EnableIT_TC(_SPIRxDMA, _SPIRxDMACh);
peu605 0:b3d998305b9d 497 LL_DMA_EnableIT_HT(_SPIRxDMA, _SPIRxDMACh);
peu605 0:b3d998305b9d 498
peu605 0:b3d998305b9d 499 // Enable DMA Channel
peu605 0:b3d998305b9d 500 LL_DMA_EnableChannel(_SPIRxDMA, _SPIRxDMACh);
peu605 0:b3d998305b9d 501 LL_DMA_EnableChannel(_SPITxDMA, _SPITxDMACh);
peu605 0:b3d998305b9d 502
peu605 0:b3d998305b9d 503 }