もっと今更、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:
Sat Sep 02 14:49:27 2017 +0000
Revision:
1:d7c7d1651f2e
Parent:
0:b3d998305b9d
Child:
2:62c8aa0c38c7
fix comment

Who changed what in which revision?

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