もっと今更、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:
Tue Sep 05 12:44:45 2017 +0000
Revision:
4:c7c69c9b3cac
Parent:
3:bdac1803f0fd
Child:
5:1141ebe337d8
add coment

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 3:bdac1803f0fd 74 // change to 72MHz
peu605 2:62c8aa0c38c7 75 SystemClock_Config();
peu605 3:bdac1803f0fd 76
peu605 0:b3d998305b9d 77 setupPeripherals();
peu605 0:b3d998305b9d 78 setChannelStatus();
peu605 3:bdac1803f0fd 79
peu605 0:b3d998305b9d 80 HAL_Delay(1000);
peu605 0:b3d998305b9d 81
peu605 0:b3d998305b9d 82 // enable SPI and deselect
peu605 0:b3d998305b9d 83 _SPI_DESELECT_SLAVE();
peu605 0:b3d998305b9d 84 _SPI_ENABLE(); // LL_SPI_Enable(_SPI);
peu605 0:b3d998305b9d 85
peu605 0:b3d998305b9d 86 uint16_t spiCR1 = _SPI->CR1 & ~SPI_CR1_SSI; // use pre calculated value
peu605 0:b3d998305b9d 87
peu605 0:b3d998305b9d 88 // LRCK Hi = Left channel
peu605 0:b3d998305b9d 89 // Wait LRCK rise and start SPI as soon as possible
peu605 0:b3d998305b9d 90 while(LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_12) != 0); // wait for falling edge
peu605 0:b3d998305b9d 91 while(LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_12) == 0); // wait for rising edge
peu605 0:b3d998305b9d 92
peu605 0:b3d998305b9d 93 // select slave
peu605 0:b3d998305b9d 94 _SPI->CR1 = spiCR1;
peu605 0:b3d998305b9d 95
peu605 0:b3d998305b9d 96 // wait for interrupt
peu605 0:b3d998305b9d 97 while (true) {
peu605 0:b3d998305b9d 98
peu605 3:bdac1803f0fd 99 __WFI();
peu605 3:bdac1803f0fd 100
peu605 2:62c8aa0c38c7 101 #ifdef _DEBUG_CONSOLE
peu605 2:62c8aa0c38c7 102 debugOut();
peu605 0:b3d998305b9d 103 #endif
peu605 0:b3d998305b9d 104
peu605 0:b3d998305b9d 105 }
peu605 0:b3d998305b9d 106 }
peu605 0:b3d998305b9d 107
peu605 0:b3d998305b9d 108
peu605 0:b3d998305b9d 109 void transferFrames()
peu605 0:b3d998305b9d 110 {
peu605 3:bdac1803f0fd 111
peu605 3:bdac1803f0fd 112 // measured load is 18.6% at 72MHz
peu605 0:b3d998305b9d 113 _LED_OFF(); // PC_13 to HIGH
peu605 3:bdac1803f0fd 114
peu605 0:b3d998305b9d 115 for (uint32_t i = 0; i < BUFFER_NUM_FRAMES / 2; ++i) {
peu605 0:b3d998305b9d 116 transferFrame();
peu605 0:b3d998305b9d 117 }
peu605 3:bdac1803f0fd 118
peu605 0:b3d998305b9d 119 _LED_ON(); // PC_13 to LOW
peu605 3:bdac1803f0fd 120
peu605 0:b3d998305b9d 121 }
peu605 0:b3d998305b9d 122
peu605 0:b3d998305b9d 123
peu605 0:b3d998305b9d 124 void transferFrame()
peu605 0:b3d998305b9d 125 {
peu605 0:b3d998305b9d 126
peu605 0:b3d998305b9d 127 static uint32_t frameIndex = 0;
peu605 0:b3d998305b9d 128 static uint32_t buffIndex = 0;
peu605 0:b3d998305b9d 129
peu605 0:b3d998305b9d 130 uint16_t *rxBuffPtr, *txBuffPtr;
peu605 0:b3d998305b9d 131
peu605 0:b3d998305b9d 132 // transfer left channel
peu605 0:b3d998305b9d 133 rxBuffPtr = (uint16_t*) &spiRxBuff[buffIndex].ltCh;
peu605 0:b3d998305b9d 134 txBuffPtr = (uint16_t*) &spiTxBuff[buffIndex].aCh;
peu605 0:b3d998305b9d 135 transferSubFrame(frameIndex, true, rxBuffPtr, txBuffPtr);
peu605 0:b3d998305b9d 136
peu605 0:b3d998305b9d 137 // transfer right channel
peu605 0:b3d998305b9d 138 rxBuffPtr = (uint16_t*) &spiRxBuff[buffIndex].rtCh;
peu605 0:b3d998305b9d 139 txBuffPtr = (uint16_t*) &spiTxBuff[buffIndex].bCh;
peu605 0:b3d998305b9d 140 transferSubFrame(frameIndex, false, rxBuffPtr, txBuffPtr);
peu605 0:b3d998305b9d 141
peu605 0:b3d998305b9d 142 if (++frameIndex == 192) {
peu605 0:b3d998305b9d 143 frameIndex = 0;
peu605 0:b3d998305b9d 144 }
peu605 0:b3d998305b9d 145 if (++buffIndex == BUFFER_NUM_FRAMES) {
peu605 0:b3d998305b9d 146 buffIndex = 0;
peu605 0:b3d998305b9d 147 }
peu605 0:b3d998305b9d 148
peu605 0:b3d998305b9d 149 }
peu605 0:b3d998305b9d 150
peu605 0:b3d998305b9d 151
peu605 0:b3d998305b9d 152 void transferSubFrame(uint32_t frameIndex, bool aCh, uint16_t *rxBuffPtr, uint16_t *txBuffPtr)
peu605 0:b3d998305b9d 153 {
peu605 0:b3d998305b9d 154
peu605 0:b3d998305b9d 155 static bool lastCellZero = true;
peu605 0:b3d998305b9d 156 // static uint32_t spiDelay = 0;
peu605 3:bdac1803f0fd 157
peu605 0:b3d998305b9d 158 // ======================================
peu605 0:b3d998305b9d 159 // Read rx buffer and make raw SPIDF data
peu605 0:b3d998305b9d 160 // ======================================
peu605 3:bdac1803f0fd 161
peu605 0:b3d998305b9d 162 // Roland SC-88pro, 256fs, 18bit right justified, MSB first
peu605 2:62c8aa0c38c7 163 // SC-88pro's output format seems to be 2's complement 18 bit audio data in 20 bit data frame.
peu605 0:b3d998305b9d 164 //
peu605 0:b3d998305b9d 165 // SPIRxBuff, each channel data have 128(=256/2) bits, M:MSB, L:LSB
peu605 2:62c8aa0c38c7 166 // 127 <--- ---> 0
peu605 2:62c8aa0c38c7 167 // 0000 ... 0000000 00000000000M==== ===============L
peu605 2:62c8aa0c38c7 168 // 1111 ... 1111111 11111111111M==== ===============L
peu605 2:62c8aa0c38c7 169 // ---- ... ------- ---------------- ----------------
peu605 0:b3d998305b9d 170 // +0 -> 5 hlf_word +6 +7
peu605 0:b3d998305b9d 171 // 1111 ... 0000000 1111110000000000 1111110000000000
peu605 0:b3d998305b9d 172 // 5432 6543210 5432109876543210 5432109876543210
peu605 0:b3d998305b9d 173 //
peu605 0:b3d998305b9d 174 // Actually, SPI starts some SCKs after LRCK change.
peu605 0:b3d998305b9d 175 // Received data are shifted leftward.
peu605 0:b3d998305b9d 176 //
peu605 2:62c8aa0c38c7 177 // 127 <--- ---> 0
peu605 2:62c8aa0c38c7 178 // |<->| spiDelay
peu605 2:62c8aa0c38c7 179 // M========= ==========L
peu605 0:b3d998305b9d 180 // ---- ... ------- ---------------- ----------------
peu605 2:62c8aa0c38c7 181 // +0 -> 5 hlf_word +6 +7
peu605 0:b3d998305b9d 182 // 1111 ... 0000000 1111110000000000 1111110000000000
peu605 0:b3d998305b9d 183 // 5432 6543210 5432109876543210 5432109876543210
peu605 0:b3d998305b9d 184 //
peu605 3:bdac1803f0fd 185 // bit[127:20] is all 0 or all 1. SDO keeps last LSB state.
peu605 0:b3d998305b9d 186 //
peu605 2:62c8aa0c38c7 187 // bit[31:20] should be 000...00 or 111...11
peu605 2:62c8aa0c38c7 188 // bit[19:0] MSB to LSB, 2's complement 18 bit audio data in 20 bit data frame
peu605 3:bdac1803f0fd 189 //
peu605 3:bdac1803f0fd 190 // measured spiDelay is 2 to 4
peu605 3:bdac1803f0fd 191
peu605 0:b3d998305b9d 192 // arithmetic right shift
peu605 0:b3d998305b9d 193 int32_t val = (*(rxBuffPtr + 6) << 16) | *(rxBuffPtr + 7);
peu605 0:b3d998305b9d 194 val >>= spiDelay;
peu605 3:bdac1803f0fd 195
peu605 0:b3d998305b9d 196 // determine spiDelay
peu605 0:b3d998305b9d 197 while(true) {
peu605 2:62c8aa0c38c7 198 int32_t test = val & MASK31_20;
peu605 2:62c8aa0c38c7 199 if (test == 0 || test == MASK31_20) {
peu605 0:b3d998305b9d 200 break;
peu605 0:b3d998305b9d 201 } else {
peu605 0:b3d998305b9d 202 if (spiDelay == MAX_SPI_DELAY) {
peu605 0:b3d998305b9d 203 spiDelay = 0;
peu605 0:b3d998305b9d 204 val = 0; // discard data
peu605 0:b3d998305b9d 205 break;
peu605 0:b3d998305b9d 206 } else {
peu605 0:b3d998305b9d 207 ++spiDelay;
peu605 0:b3d998305b9d 208 val >>= 1;
peu605 0:b3d998305b9d 209 }
peu605 0:b3d998305b9d 210 }
peu605 0:b3d998305b9d 211 }
peu605 3:bdac1803f0fd 212
peu605 3:bdac1803f0fd 213 // left shift to fit 24 bit width, adding zero
peu605 0:b3d998305b9d 214 val <<= (24 - SDATA_LENGH);
peu605 0:b3d998305b9d 215
peu605 0:b3d998305b9d 216 // 4-27 data, 28 V, 29 U, 30 C, 31 P
peu605 0:b3d998305b9d 217 // U = 0
peu605 0:b3d998305b9d 218 // 'val' here does not have preamble.
peu605 0:b3d998305b9d 219 // So, V position is (28 - 4), C pos is (30 - 4), and P pos is (31 - 4).
peu605 3:bdac1803f0fd 220
peu605 0:b3d998305b9d 221 // mask with 24 bit to clear VUCP bits
peu605 2:62c8aa0c38c7 222 val &= MASK23_0;
peu605 0:b3d998305b9d 223
peu605 0:b3d998305b9d 224 // set Channel status bit
peu605 0:b3d998305b9d 225 uint32_t bitPos = frameIndex & 7;
peu605 0:b3d998305b9d 226 uint32_t offset = frameIndex >> 3;
peu605 0:b3d998305b9d 227 uint8_t *chStatusPtr = aCh
peu605 0:b3d998305b9d 228 ? (uint8_t*) &channelStatus[offset].ltCh
peu605 0:b3d998305b9d 229 : (uint8_t*) &channelStatus[offset].rtCh;
peu605 0:b3d998305b9d 230 if (*chStatusPtr & _BV(bitPos)) {
peu605 0:b3d998305b9d 231 val |= _BV(30 - 4);
peu605 0:b3d998305b9d 232 }
peu605 0:b3d998305b9d 233
peu605 0:b3d998305b9d 234 // set parity bit
peu605 0:b3d998305b9d 235 if (oddParity(val)) {
peu605 0:b3d998305b9d 236 val |= _BV(31 - 4);
peu605 0:b3d998305b9d 237 }
peu605 0:b3d998305b9d 238
peu605 1:d7c7d1651f2e 239 // ===============================================
peu605 1:d7c7d1651f2e 240 // Biphase Mark Code encode and write to Tx buffer
peu605 1:d7c7d1651f2e 241 // ===============================================
peu605 0:b3d998305b9d 242
peu605 0:b3d998305b9d 243 // Z:preamble, A:aux, L:LSB, M:MSB, 0:filler(unused bit)
peu605 0:b3d998305b9d 244 // V:validity, U:user, C:ch status, P:parity
peu605 2:62c8aa0c38c7 245 // ===> BMC encode from LSB to MSB
peu605 0:b3d998305b9d 246 //(PCUVM================L00AAAAZZZZ)
peu605 0:b3d998305b9d 247 // PCUVM================L00AAAA w/o preamble (= val)
peu605 0:b3d998305b9d 248 // --------------------------------
peu605 0:b3d998305b9d 249 // 33222222222211111111110000000000
peu605 0:b3d998305b9d 250 // 10987654321098765432109876543210
peu605 0:b3d998305b9d 251
peu605 0:b3d998305b9d 252 // Write Biphase Mark Code data to SPITx-DMA buffer
peu605 0:b3d998305b9d 253 // First, 0 ~ 4 bit is Preamble. Not BMC!
peu605 0:b3d998305b9d 254 uint16_t bmc;
peu605 2:62c8aa0c38c7 255 if (!aCh) {
peu605 3:bdac1803f0fd 256 // b channel
peu605 2:62c8aa0c38c7 257 bmc = lastCellZero ? PREAMBLE_Y : ~PREAMBLE_Y;
peu605 2:62c8aa0c38c7 258 } else if (frameIndex == 0) {
peu605 3:bdac1803f0fd 259 // a channel, frame 0
peu605 0:b3d998305b9d 260 bmc = lastCellZero ? PREAMBLE_Z : ~PREAMBLE_Z;
peu605 2:62c8aa0c38c7 261 } else {
peu605 3:bdac1803f0fd 262 // a channel, frame != 0
peu605 0:b3d998305b9d 263 bmc = lastCellZero ? PREAMBLE_X : ~PREAMBLE_X;
peu605 0:b3d998305b9d 264 }
peu605 3:bdac1803f0fd 265 // lastCellZero = !(bmc & 1);
peu605 3:bdac1803f0fd 266 lastCellZero = (bmc & 1) == 0;
peu605 0:b3d998305b9d 267 *txBuffPtr++ = bmc;
peu605 0:b3d998305b9d 268
peu605 1:d7c7d1651f2e 269 // Next, 5 ~ 31 bit, audio data and VUCP bits. 28/4 = 7 loops
peu605 0:b3d998305b9d 270 // BMC encode each by lower 4 bits
peu605 0:b3d998305b9d 271 for (uint32_t i = 0; i < 7 ; ++i) {
peu605 0:b3d998305b9d 272 bmc = lastCellZero
peu605 0:b3d998305b9d 273 ? bmcTable[val & 0x0f] : ~bmcTable[val & 0x0f];
peu605 3:bdac1803f0fd 274 // lastCellZero = !(bmc & 1);
peu605 3:bdac1803f0fd 275 lastCellZero = (bmc & 1) == 0;
peu605 0:b3d998305b9d 276 *txBuffPtr++ = bmc;
peu605 0:b3d998305b9d 277 val >>= 4;
peu605 0:b3d998305b9d 278 }
peu605 0:b3d998305b9d 279
peu605 0:b3d998305b9d 280 }
peu605 0:b3d998305b9d 281
peu605 0:b3d998305b9d 282
peu605 0:b3d998305b9d 283 // consumer, copy allowed, 18bit, 32kHz
peu605 0:b3d998305b9d 284 void setChannelStatus()
peu605 0:b3d998305b9d 285 {
peu605 0:b3d998305b9d 286
peu605 0:b3d998305b9d 287 // Byte 0: General control and mode information
peu605 0:b3d998305b9d 288 // copy enable
peu605 0:b3d998305b9d 289 channelStatus[0].ltCh = _BV(C_COPY);
peu605 0:b3d998305b9d 290 channelStatus[0].rtCh = _BV(C_COPY);
peu605 0:b3d998305b9d 291
peu605 0:b3d998305b9d 292 // Byte 1: Category code
peu605 0:b3d998305b9d 293 // general
peu605 0:b3d998305b9d 294 channelStatus[1].ltCh = 0;
peu605 0:b3d998305b9d 295 channelStatus[1].rtCh = 0;
peu605 0:b3d998305b9d 296
peu605 0:b3d998305b9d 297 // Byte 2: Source and channel number
peu605 0:b3d998305b9d 298 channelStatus[2].ltCh = 0b0001 << 4;
peu605 0:b3d998305b9d 299 channelStatus[2].rtCh = 0b0010 << 4;
peu605 0:b3d998305b9d 300
peu605 0:b3d998305b9d 301 // Byte 3: Sampling frequency and clock accuracy
peu605 0:b3d998305b9d 302 channelStatus[3].ltCh = _BV(C_FS1) | _BV(C_FS0);
peu605 0:b3d998305b9d 303 channelStatus[3].rtCh = _BV(C_FS1) | _BV(C_FS0);
peu605 0:b3d998305b9d 304
peu605 0:b3d998305b9d 305 // Byte 23: CRC
peu605 0:b3d998305b9d 306 uint8_t *chStatusPtr = (uint8_t*) channelStatus;
peu605 0:b3d998305b9d 307 channelStatus[23].ltCh = calcCRC(chStatusPtr);
peu605 0:b3d998305b9d 308 ++chStatusPtr;
peu605 0:b3d998305b9d 309 channelStatus[23].rtCh = calcCRC(chStatusPtr);
peu605 0:b3d998305b9d 310
peu605 0:b3d998305b9d 311 }
peu605 0:b3d998305b9d 312
peu605 0:b3d998305b9d 313
peu605 0:b3d998305b9d 314 uint32_t oddParity(uint32_t val)
peu605 0:b3d998305b9d 315 {
peu605 0:b3d998305b9d 316 val ^= val >> 16;
peu605 0:b3d998305b9d 317 val ^= val >> 8;
peu605 0:b3d998305b9d 318 val ^= val >> 4;
peu605 0:b3d998305b9d 319 val ^= val >> 2;
peu605 0:b3d998305b9d 320 val ^= val >> 1;
peu605 0:b3d998305b9d 321 return val & 1;
peu605 0:b3d998305b9d 322 }
peu605 0:b3d998305b9d 323
peu605 0:b3d998305b9d 324
peu605 0:b3d998305b9d 325 uint8_t calcCRC(uint8_t *chStatusPtr)
peu605 0:b3d998305b9d 326 {
peu605 0:b3d998305b9d 327 uint8_t crc = 255;
peu605 0:b3d998305b9d 328 for (uint32_t i = 0; i < 24; ++i) {
peu605 0:b3d998305b9d 329 uint8_t b = *chStatusPtr;
peu605 0:b3d998305b9d 330 for (uint32_t j = 0; j < 8; ++j) {
peu605 0:b3d998305b9d 331 if ((crc & 1) ^ (b & 1)) {
peu605 0:b3d998305b9d 332 crc >>= 1;
peu605 0:b3d998305b9d 333 crc ^= 0xb8;
peu605 0:b3d998305b9d 334 } else {
peu605 0:b3d998305b9d 335 crc >>= 1;
peu605 0:b3d998305b9d 336 }
peu605 0:b3d998305b9d 337 b >>= 1;
peu605 0:b3d998305b9d 338 }
peu605 0:b3d998305b9d 339 chStatusPtr += 2;
peu605 0:b3d998305b9d 340 }
peu605 0:b3d998305b9d 341 return crc;
peu605 0:b3d998305b9d 342 }
peu605 0:b3d998305b9d 343
peu605 0:b3d998305b9d 344
peu605 2:62c8aa0c38c7 345 void toBinary(uint16_t *val_ptr, char *str)
peu605 2:62c8aa0c38c7 346 {
peu605 2:62c8aa0c38c7 347 uint16_t val = *val_ptr;
peu605 2:62c8aa0c38c7 348 for (uint32_t j = 0; j < 16; ++j) {
peu605 2:62c8aa0c38c7 349 *str = val & 0x8000 ? '1' : '0';
peu605 2:62c8aa0c38c7 350 val <<= 1;
peu605 2:62c8aa0c38c7 351 ++str;
peu605 2:62c8aa0c38c7 352 }
peu605 2:62c8aa0c38c7 353 *str = '\0';
peu605 2:62c8aa0c38c7 354 }
peu605 2:62c8aa0c38c7 355
peu605 3:bdac1803f0fd 356
peu605 2:62c8aa0c38c7 357 #ifdef _DEBUG_CONSOLE
peu605 2:62c8aa0c38c7 358 void debugOut()
peu605 2:62c8aa0c38c7 359 {
peu605 3:bdac1803f0fd 360 static char str[17];
peu605 3:bdac1803f0fd 361 static Serial pc(PA_2, PA_3);
peu605 3:bdac1803f0fd 362
peu605 2:62c8aa0c38c7 363 // pc.printf("SystemCoreClock =%d\n", SystemCoreClock);
peu605 2:62c8aa0c38c7 364
peu605 3:bdac1803f0fd 365 /*
peu605 3:bdac1803f0fd 366 // dump raw data
peu605 3:bdac1803f0fd 367 uint16_t tmp = spiRxBuff[0].ltCh[6];
peu605 3:bdac1803f0fd 368 toBinary(&tmp, (char*) &str);
peu605 3:bdac1803f0fd 369 pc.printf("Delay:%02d %s ", spiDelay, str);
peu605 3:bdac1803f0fd 370 tmp = spiRxBuff[0].ltCh[7];
peu605 3:bdac1803f0fd 371 toBinary(&tmp, (char*) &str);
peu605 3:bdac1803f0fd 372 pc.printf("%s\n", str);
peu605 3:bdac1803f0fd 373 HAL_Delay(200);
peu605 3:bdac1803f0fd 374 */
peu605 3:bdac1803f0fd 375
peu605 3:bdac1803f0fd 376 // dump shifted data
peu605 3:bdac1803f0fd 377 int32_t val = (spiRxBuff[0].ltCh[6] << 16) | (spiRxBuff[0].ltCh[7]);
peu605 3:bdac1803f0fd 378 val >>= spiDelay;
peu605 3:bdac1803f0fd 379 uint16_t tmp = (val & 0xffff0000) >> 16;
peu605 3:bdac1803f0fd 380 toBinary(&tmp, (char*) &str);
peu605 3:bdac1803f0fd 381 pc.printf("Delay:%02d %s ", spiDelay, str);
peu605 3:bdac1803f0fd 382 tmp = val & 0xffff;
peu605 3:bdac1803f0fd 383 toBinary(&tmp, (char*) &str);
peu605 3:bdac1803f0fd 384 pc.printf("%s\n", str);
peu605 3:bdac1803f0fd 385 HAL_Delay(200);
peu605 3:bdac1803f0fd 386
peu605 3:bdac1803f0fd 387 /*
peu605 3:bdac1803f0fd 388 // find loud 18bit data
peu605 3:bdac1803f0fd 389 int32_t val = (spiRxBuff[0].ltCh[6] << 16) | (spiRxBuff[0].ltCh[7]);
peu605 3:bdac1803f0fd 390 val >>= spiDelay;
peu605 3:bdac1803f0fd 391 uint16_t tmp = (val & 0xffff0000) >> 16;
peu605 3:bdac1803f0fd 392 if ((tmp & 0b1111) == 0b1110 || (tmp & 0b1111) == 0b0001) {
peu605 3:bdac1803f0fd 393 toBinary(&tmp, (char*) &str);
peu605 3:bdac1803f0fd 394 pc.printf("Delay:%02d %s ", spiDelay, str);
peu605 3:bdac1803f0fd 395 tmp = val & 0xffff;
peu605 3:bdac1803f0fd 396 toBinary(&tmp, (char*) &str);
peu605 3:bdac1803f0fd 397 pc.printf("%s\n", str);
peu605 2:62c8aa0c38c7 398 }
peu605 3:bdac1803f0fd 399 */
peu605 3:bdac1803f0fd 400
peu605 2:62c8aa0c38c7 401 }
peu605 2:62c8aa0c38c7 402 #endif
peu605 2:62c8aa0c38c7 403
peu605 3:bdac1803f0fd 404
peu605 2:62c8aa0c38c7 405 /**
peu605 2:62c8aa0c38c7 406 * @brief System Clock Configuration
peu605 2:62c8aa0c38c7 407 * The system Clock is configured as follow :
peu605 2:62c8aa0c38c7 408 * System Clock source = PLL (HSE)
peu605 2:62c8aa0c38c7 409 * SYSCLK(Hz) = 72000000
peu605 2:62c8aa0c38c7 410 * HCLK(Hz) = 72000000
peu605 2:62c8aa0c38c7 411 * AHB Prescaler = 1
peu605 2:62c8aa0c38c7 412 * APB1 Prescaler = 2
peu605 2:62c8aa0c38c7 413 * APB2 Prescaler = 1
peu605 2:62c8aa0c38c7 414 * HSE Frequency(Hz) = 8000000
peu605 2:62c8aa0c38c7 415 * PLLMUL = 9
peu605 2:62c8aa0c38c7 416 * Flash Latency(WS) = 2
peu605 2:62c8aa0c38c7 417 * @param None
peu605 2:62c8aa0c38c7 418 * @retval None
peu605 2:62c8aa0c38c7 419 */
peu605 2:62c8aa0c38c7 420 void SystemClock_Config(void)
peu605 2:62c8aa0c38c7 421 {
peu605 3:bdac1803f0fd 422 HAL_RCC_DeInit();
peu605 3:bdac1803f0fd 423 // not implemented yet?
peu605 3:bdac1803f0fd 424 // LL_RCC_DeInit();
peu605 2:62c8aa0c38c7 425
peu605 2:62c8aa0c38c7 426 /* Set FLASH latency */
peu605 2:62c8aa0c38c7 427 LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
peu605 2:62c8aa0c38c7 428
peu605 2:62c8aa0c38c7 429 /* Enable HSE oscillator */
peu605 2:62c8aa0c38c7 430 LL_RCC_HSE_Enable();
peu605 2:62c8aa0c38c7 431 while(LL_RCC_HSE_IsReady() != 1) {
peu605 2:62c8aa0c38c7 432 };
peu605 2:62c8aa0c38c7 433
peu605 2:62c8aa0c38c7 434 /* Main PLL configuration and activation */
peu605 2:62c8aa0c38c7 435 LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE_DIV_1, LL_RCC_PLL_MUL_9);
peu605 2:62c8aa0c38c7 436
peu605 2:62c8aa0c38c7 437 LL_RCC_PLL_Enable();
peu605 2:62c8aa0c38c7 438 while(LL_RCC_PLL_IsReady() != 1) {
peu605 2:62c8aa0c38c7 439 };
peu605 2:62c8aa0c38c7 440
peu605 2:62c8aa0c38c7 441 /* Sysclk activation on the main PLL */
peu605 2:62c8aa0c38c7 442 LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
peu605 2:62c8aa0c38c7 443 LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
peu605 2:62c8aa0c38c7 444 while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
peu605 2:62c8aa0c38c7 445 };
peu605 2:62c8aa0c38c7 446
peu605 2:62c8aa0c38c7 447 /* Set APB1 & APB2 prescaler*/
peu605 2:62c8aa0c38c7 448 LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
peu605 2:62c8aa0c38c7 449 LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
peu605 2:62c8aa0c38c7 450
peu605 2:62c8aa0c38c7 451 /* Set systick to 1ms in using frequency set to 72MHz */
peu605 2:62c8aa0c38c7 452 LL_Init1msTick(72000000);
peu605 2:62c8aa0c38c7 453
peu605 2:62c8aa0c38c7 454 /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
peu605 2:62c8aa0c38c7 455 LL_SetSystemCoreClock(72000000);
peu605 2:62c8aa0c38c7 456
peu605 3:bdac1803f0fd 457 // re-set baud rate.
peu605 3:bdac1803f0fd 458 // pc.baud(9600);
peu605 2:62c8aa0c38c7 459 }
peu605 2:62c8aa0c38c7 460
peu605 2:62c8aa0c38c7 461
peu605 0:b3d998305b9d 462 void setupPeripherals()
peu605 0:b3d998305b9d 463 {
peu605 3:bdac1803f0fd 464
peu605 0:b3d998305b9d 465 // enable GPIOB/C clock
peu605 0:b3d998305b9d 466 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
peu605 0:b3d998305b9d 467 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
peu605 0:b3d998305b9d 468
peu605 0:b3d998305b9d 469 // Configure GPIO pin : LED_Pin, PC13, OUTPUT
peu605 0:b3d998305b9d 470 LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_OUTPUT);
peu605 0:b3d998305b9d 471 LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_13, LL_GPIO_OUTPUT_PUSHPULL);
peu605 0:b3d998305b9d 472 LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 473
peu605 0:b3d998305b9d 474 // SPI IO pins
peu605 0:b3d998305b9d 475 // PB13 -> SCK, 5V tolerant
peu605 0:b3d998305b9d 476 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_13, LL_GPIO_MODE_ALTERNATE);
peu605 0:b3d998305b9d 477 LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_13, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 478 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 479 // PB14 -> MISO, 5V tolerant
peu605 0:b3d998305b9d 480 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_14, LL_GPIO_MODE_ALTERNATE);
peu605 0:b3d998305b9d 481 LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_14, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 482 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_14, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 483 // PB15 -> MOSI, 5V tolerant
peu605 0:b3d998305b9d 484 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_15, LL_GPIO_MODE_ALTERNATE);
peu605 0:b3d998305b9d 485 LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_15, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 486 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_15, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 487 // PB12 -> LRCK, 5V tolerant
peu605 0:b3d998305b9d 488 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_12, LL_GPIO_MODE_INPUT);
peu605 0:b3d998305b9d 489 // LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_12, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 490 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_12, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 491
peu605 0:b3d998305b9d 492 // SPI Slave full duplex, mode 0, 16bit
peu605 0:b3d998305b9d 493 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); // SPI2
peu605 0:b3d998305b9d 494 LL_SPI_SetMode(_SPI, LL_SPI_MODE_SLAVE);
peu605 0:b3d998305b9d 495 LL_SPI_SetTransferDirection(_SPI,LL_SPI_FULL_DUPLEX);
peu605 0:b3d998305b9d 496 LL_SPI_SetClockPhase(_SPI, LL_SPI_PHASE_1EDGE);
peu605 0:b3d998305b9d 497 LL_SPI_SetClockPolarity(_SPI, LL_SPI_POLARITY_LOW);
peu605 0:b3d998305b9d 498 LL_SPI_SetTransferBitOrder(_SPI, LL_SPI_MSB_FIRST);
peu605 0:b3d998305b9d 499 LL_SPI_SetDataWidth(_SPI, LL_SPI_DATAWIDTH_16BIT);
peu605 0:b3d998305b9d 500 LL_SPI_SetNSSMode(_SPI, LL_SPI_NSS_SOFT);
peu605 0:b3d998305b9d 501
peu605 0:b3d998305b9d 502 // connect to DMAReq
peu605 0:b3d998305b9d 503 LL_SPI_EnableDMAReq_RX(_SPI);
peu605 0:b3d998305b9d 504 LL_SPI_EnableDMAReq_TX(_SPI);
peu605 0:b3d998305b9d 505
peu605 0:b3d998305b9d 506
peu605 0:b3d998305b9d 507 // DMA
peu605 0:b3d998305b9d 508 LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); // DMA1
peu605 0:b3d998305b9d 509 // _SPIRxDMA, DMA1 Channel 4
peu605 0:b3d998305b9d 510 LL_DMA_ConfigTransfer(_SPIRxDMA, _SPIRxDMACh,
peu605 0:b3d998305b9d 511 LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_CIRCULAR |
peu605 0:b3d998305b9d 512 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
peu605 0:b3d998305b9d 513 LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD);
peu605 0:b3d998305b9d 514 LL_DMA_ConfigAddresses(_SPIRxDMA, _SPIRxDMACh,
peu605 0:b3d998305b9d 515 (uint32_t)&(_SPI->DR), (uint32_t)&spiRxBuff,
peu605 0:b3d998305b9d 516 LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
peu605 0:b3d998305b9d 517 LL_DMA_SetDataLength(_SPIRxDMA, _SPIRxDMACh, DMA_TRANSFER_LENGTH);
peu605 0:b3d998305b9d 518
peu605 0:b3d998305b9d 519 // _SPITxDMA, DMA1 Channel5
peu605 0:b3d998305b9d 520 LL_DMA_ConfigTransfer(_SPITxDMA, _SPITxDMACh,
peu605 0:b3d998305b9d 521 LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_MEDIUM | LL_DMA_MODE_CIRCULAR |
peu605 0:b3d998305b9d 522 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
peu605 0:b3d998305b9d 523 LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD);
peu605 0:b3d998305b9d 524 LL_DMA_ConfigAddresses(_SPITxDMA, _SPITxDMACh,
peu605 0:b3d998305b9d 525 (uint32_t)&spiTxBuff, (uint32_t)&(_SPI->DR),
peu605 0:b3d998305b9d 526 LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
peu605 0:b3d998305b9d 527 LL_DMA_SetDataLength(_SPITxDMA, _SPITxDMACh, DMA_TRANSFER_LENGTH);
peu605 0:b3d998305b9d 528
peu605 0:b3d998305b9d 529 // Enable SPIRx DMA IRQ, Half Transfer and Transfer Complete
peu605 0:b3d998305b9d 530 NVIC_SetPriority(_SPIRxDMAIRQn, 0);
peu605 0:b3d998305b9d 531 NVIC_EnableIRQ(_SPIRxDMAIRQn);
peu605 0:b3d998305b9d 532
peu605 0:b3d998305b9d 533 LL_DMA_EnableIT_TC(_SPIRxDMA, _SPIRxDMACh);
peu605 0:b3d998305b9d 534 LL_DMA_EnableIT_HT(_SPIRxDMA, _SPIRxDMACh);
peu605 0:b3d998305b9d 535
peu605 0:b3d998305b9d 536 // Enable DMA Channel
peu605 0:b3d998305b9d 537 LL_DMA_EnableChannel(_SPIRxDMA, _SPIRxDMACh);
peu605 0:b3d998305b9d 538 LL_DMA_EnableChannel(_SPITxDMA, _SPITxDMACh);
peu605 0:b3d998305b9d 539
peu605 0:b3d998305b9d 540 }
peu605 4:c7c69c9b3cac 541
peu605 4:c7c69c9b3cac 542 /*
peu605 4:c7c69c9b3cac 543 // Use java to create BMC table, because I am a javaer.
peu605 4:c7c69c9b3cac 544
peu605 4:c7c69c9b3cac 545 private void start() {
peu605 4:c7c69c9b3cac 546 StringBuilder sb = new StringBuilder();
peu605 4:c7c69c9b3cac 547 for (char i = 0; i < 16; ++i) {
peu605 4:c7c69c9b3cac 548 sb.append(String.format("%02d", (int) i)).append(" = 0b");
peu605 4:c7c69c9b3cac 549 boolean lastCellZero = true;
peu605 4:c7c69c9b3cac 550 char c = i;
peu605 4:c7c69c9b3cac 551 for (int j = 0; j < 4; ++j) {
peu605 4:c7c69c9b3cac 552 if ((c & 1) == 0) {
peu605 4:c7c69c9b3cac 553 if (lastCellZero) {
peu605 4:c7c69c9b3cac 554 sb.append("1111");
peu605 4:c7c69c9b3cac 555 lastCellZero = false;
peu605 4:c7c69c9b3cac 556 } else {
peu605 4:c7c69c9b3cac 557 sb.append("0000");
peu605 4:c7c69c9b3cac 558 lastCellZero = true;
peu605 4:c7c69c9b3cac 559 }
peu605 4:c7c69c9b3cac 560 } else {
peu605 4:c7c69c9b3cac 561 if (lastCellZero) {
peu605 4:c7c69c9b3cac 562 sb.append("1100");
peu605 4:c7c69c9b3cac 563 lastCellZero = true;
peu605 4:c7c69c9b3cac 564 } else {
peu605 4:c7c69c9b3cac 565 sb.append("0011");
peu605 4:c7c69c9b3cac 566 lastCellZero = false;
peu605 4:c7c69c9b3cac 567 }
peu605 4:c7c69c9b3cac 568 }
peu605 4:c7c69c9b3cac 569 c >>= 1;
peu605 4:c7c69c9b3cac 570 }
peu605 4:c7c69c9b3cac 571 sb.append('\n');
peu605 4:c7c69c9b3cac 572 }
peu605 4:c7c69c9b3cac 573 System.out.println(sb.toString());
peu605 4:c7c69c9b3cac 574 }
peu605 4:c7c69c9b3cac 575 */