もっと今更、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 12 07:41:48 2017 +0000
Revision:
11:79658b6d3f39
Parent:
10:bbf0ab5cc56f
remove CRC form channel status

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 5:1141ebe337d8 53 // Serial pc(PA_2, PA_3);
peu605 5:1141ebe337d8 54
peu605 0:b3d998305b9d 55
peu605 0:b3d998305b9d 56 extern "C" void DMA1_Channel4_IRQHandler(void)
peu605 0:b3d998305b9d 57 {
peu605 0:b3d998305b9d 58
peu605 0:b3d998305b9d 59 // SPI Rx DMA
peu605 0:b3d998305b9d 60 if(LL_DMA_IsActiveFlag_HT4(_SPIRxDMA)) {
peu605 0:b3d998305b9d 61 // half transfer
peu605 0:b3d998305b9d 62 LL_DMA_ClearFlag_HT4(_SPIRxDMA);
peu605 0:b3d998305b9d 63 transferFrames();
peu605 0:b3d998305b9d 64
peu605 0:b3d998305b9d 65 } else if (LL_DMA_IsActiveFlag_TC4(_SPIRxDMA)) {
peu605 0:b3d998305b9d 66 // transfer complete
peu605 0:b3d998305b9d 67 LL_DMA_ClearFlag_TC4(_SPIRxDMA);
peu605 0:b3d998305b9d 68 transferFrames();
peu605 0:b3d998305b9d 69 }
peu605 0:b3d998305b9d 70
peu605 0:b3d998305b9d 71 }
peu605 0:b3d998305b9d 72
peu605 0:b3d998305b9d 73
peu605 0:b3d998305b9d 74 int main()
peu605 0:b3d998305b9d 75 {
peu605 3:bdac1803f0fd 76 // change to 72MHz
peu605 2:62c8aa0c38c7 77 SystemClock_Config();
peu605 3:bdac1803f0fd 78
peu605 0:b3d998305b9d 79 setupPeripherals();
peu605 0:b3d998305b9d 80 setChannelStatus();
peu605 3:bdac1803f0fd 81
peu605 0:b3d998305b9d 82 HAL_Delay(1000);
peu605 0:b3d998305b9d 83
peu605 0:b3d998305b9d 84 // enable SPI and deselect
peu605 0:b3d998305b9d 85 _SPI_DESELECT_SLAVE();
peu605 0:b3d998305b9d 86 _SPI_ENABLE(); // LL_SPI_Enable(_SPI);
peu605 0:b3d998305b9d 87
peu605 0:b3d998305b9d 88 uint16_t spiCR1 = _SPI->CR1 & ~SPI_CR1_SSI; // use pre calculated value
peu605 0:b3d998305b9d 89
peu605 0:b3d998305b9d 90 // LRCK Hi = Left channel
peu605 0:b3d998305b9d 91 // Wait LRCK rise and start SPI as soon as possible
peu605 0:b3d998305b9d 92 while(LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_12) != 0); // wait for falling edge
peu605 0:b3d998305b9d 93 while(LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_12) == 0); // wait for rising edge
peu605 0:b3d998305b9d 94
peu605 0:b3d998305b9d 95 // select slave
peu605 0:b3d998305b9d 96 _SPI->CR1 = spiCR1;
peu605 0:b3d998305b9d 97
peu605 0:b3d998305b9d 98 // wait for interrupt
peu605 0:b3d998305b9d 99 while (true) {
peu605 0:b3d998305b9d 100
peu605 3:bdac1803f0fd 101 __WFI();
peu605 3:bdac1803f0fd 102
peu605 2:62c8aa0c38c7 103 #ifdef _DEBUG_CONSOLE
peu605 2:62c8aa0c38c7 104 debugOut();
peu605 0:b3d998305b9d 105 #endif
peu605 0:b3d998305b9d 106
peu605 0:b3d998305b9d 107 }
peu605 0:b3d998305b9d 108 }
peu605 0:b3d998305b9d 109
peu605 0:b3d998305b9d 110
peu605 0:b3d998305b9d 111 void transferFrames()
peu605 0:b3d998305b9d 112 {
peu605 3:bdac1803f0fd 113
peu605 3:bdac1803f0fd 114 // measured load is 18.6% at 72MHz
peu605 0:b3d998305b9d 115 _LED_OFF(); // PC_13 to HIGH
peu605 3:bdac1803f0fd 116
peu605 0:b3d998305b9d 117 for (uint32_t i = 0; i < BUFFER_NUM_FRAMES / 2; ++i) {
peu605 0:b3d998305b9d 118 transferFrame();
peu605 0:b3d998305b9d 119 }
peu605 3:bdac1803f0fd 120
peu605 0:b3d998305b9d 121 _LED_ON(); // PC_13 to LOW
peu605 3:bdac1803f0fd 122
peu605 0:b3d998305b9d 123 }
peu605 0:b3d998305b9d 124
peu605 0:b3d998305b9d 125
peu605 0:b3d998305b9d 126 void transferFrame()
peu605 0:b3d998305b9d 127 {
peu605 0:b3d998305b9d 128
peu605 0:b3d998305b9d 129 static uint32_t frameIndex = 0;
peu605 0:b3d998305b9d 130 static uint32_t buffIndex = 0;
peu605 0:b3d998305b9d 131
peu605 0:b3d998305b9d 132 uint16_t *rxBuffPtr, *txBuffPtr;
peu605 0:b3d998305b9d 133
peu605 0:b3d998305b9d 134 // transfer left channel
peu605 0:b3d998305b9d 135 rxBuffPtr = (uint16_t*) &spiRxBuff[buffIndex].ltCh;
peu605 0:b3d998305b9d 136 txBuffPtr = (uint16_t*) &spiTxBuff[buffIndex].aCh;
peu605 0:b3d998305b9d 137 transferSubFrame(frameIndex, true, rxBuffPtr, txBuffPtr);
peu605 0:b3d998305b9d 138
peu605 0:b3d998305b9d 139 // transfer right channel
peu605 0:b3d998305b9d 140 rxBuffPtr = (uint16_t*) &spiRxBuff[buffIndex].rtCh;
peu605 0:b3d998305b9d 141 txBuffPtr = (uint16_t*) &spiTxBuff[buffIndex].bCh;
peu605 0:b3d998305b9d 142 transferSubFrame(frameIndex, false, rxBuffPtr, txBuffPtr);
peu605 0:b3d998305b9d 143
peu605 0:b3d998305b9d 144 if (++frameIndex == 192) {
peu605 0:b3d998305b9d 145 frameIndex = 0;
peu605 0:b3d998305b9d 146 }
peu605 0:b3d998305b9d 147 if (++buffIndex == BUFFER_NUM_FRAMES) {
peu605 0:b3d998305b9d 148 buffIndex = 0;
peu605 0:b3d998305b9d 149 }
peu605 0:b3d998305b9d 150
peu605 0:b3d998305b9d 151 }
peu605 0:b3d998305b9d 152
peu605 0:b3d998305b9d 153
peu605 0:b3d998305b9d 154 void transferSubFrame(uint32_t frameIndex, bool aCh, uint16_t *rxBuffPtr, uint16_t *txBuffPtr)
peu605 0:b3d998305b9d 155 {
peu605 0:b3d998305b9d 156
peu605 0:b3d998305b9d 157 static bool lastCellZero = true;
peu605 0:b3d998305b9d 158 // static uint32_t spiDelay = 0;
peu605 3:bdac1803f0fd 159
peu605 0:b3d998305b9d 160 // ======================================
peu605 0:b3d998305b9d 161 // Read rx buffer and make raw SPIDF data
peu605 0:b3d998305b9d 162 // ======================================
peu605 3:bdac1803f0fd 163
peu605 0:b3d998305b9d 164 // Roland SC-88pro, 256fs, 18bit right justified, MSB first
peu605 2:62c8aa0c38c7 165 // SC-88pro's output format seems to be 2's complement 18 bit audio data in 20 bit data frame.
peu605 0:b3d998305b9d 166 //
peu605 0:b3d998305b9d 167 // SPIRxBuff, each channel data have 128(=256/2) bits, M:MSB, L:LSB
peu605 2:62c8aa0c38c7 168 // 127 <--- ---> 0
peu605 2:62c8aa0c38c7 169 // 0000 ... 0000000 00000000000M==== ===============L
peu605 2:62c8aa0c38c7 170 // 1111 ... 1111111 11111111111M==== ===============L
peu605 2:62c8aa0c38c7 171 // ---- ... ------- ---------------- ----------------
peu605 0:b3d998305b9d 172 // +0 -> 5 hlf_word +6 +7
peu605 0:b3d998305b9d 173 // 1111 ... 0000000 1111110000000000 1111110000000000
peu605 0:b3d998305b9d 174 // 5432 6543210 5432109876543210 5432109876543210
peu605 0:b3d998305b9d 175 //
peu605 0:b3d998305b9d 176 // Actually, SPI starts some SCKs after LRCK change.
peu605 0:b3d998305b9d 177 // Received data are shifted leftward.
peu605 0:b3d998305b9d 178 //
peu605 2:62c8aa0c38c7 179 // 127 <--- ---> 0
peu605 2:62c8aa0c38c7 180 // |<->| spiDelay
peu605 2:62c8aa0c38c7 181 // M========= ==========L
peu605 0:b3d998305b9d 182 // ---- ... ------- ---------------- ----------------
peu605 2:62c8aa0c38c7 183 // +0 -> 5 hlf_word +6 +7
peu605 0:b3d998305b9d 184 // 1111 ... 0000000 1111110000000000 1111110000000000
peu605 0:b3d998305b9d 185 // 5432 6543210 5432109876543210 5432109876543210
peu605 0:b3d998305b9d 186 //
peu605 3:bdac1803f0fd 187 // bit[127:20] is all 0 or all 1. SDO keeps last LSB state.
peu605 0:b3d998305b9d 188 //
peu605 2:62c8aa0c38c7 189 // bit[31:20] should be 000...00 or 111...11
peu605 2:62c8aa0c38c7 190 // bit[19:0] MSB to LSB, 2's complement 18 bit audio data in 20 bit data frame
peu605 3:bdac1803f0fd 191 //
peu605 3:bdac1803f0fd 192 // measured spiDelay is 2 to 4
peu605 3:bdac1803f0fd 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 3:bdac1803f0fd 197
peu605 0:b3d998305b9d 198 // determine spiDelay
peu605 0:b3d998305b9d 199 while(true) {
peu605 2:62c8aa0c38c7 200 int32_t test = val & MASK31_20;
peu605 2:62c8aa0c38c7 201 if (test == 0 || test == MASK31_20) {
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 3:bdac1803f0fd 214
peu605 3:bdac1803f0fd 215 // left shift to fit 24 bit width, adding zero
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 3:bdac1803f0fd 222
peu605 0:b3d998305b9d 223 // mask with 24 bit to clear VUCP bits
peu605 2:62c8aa0c38c7 224 val &= MASK23_0;
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 2:62c8aa0c38c7 247 // ===> BMC encode from LSB to MSB
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 2:62c8aa0c38c7 257 if (!aCh) {
peu605 3:bdac1803f0fd 258 // b channel
peu605 2:62c8aa0c38c7 259 bmc = lastCellZero ? PREAMBLE_Y : ~PREAMBLE_Y;
peu605 2:62c8aa0c38c7 260 } else if (frameIndex == 0) {
peu605 3:bdac1803f0fd 261 // a channel, frame 0
peu605 0:b3d998305b9d 262 bmc = lastCellZero ? PREAMBLE_Z : ~PREAMBLE_Z;
peu605 2:62c8aa0c38c7 263 } else {
peu605 3:bdac1803f0fd 264 // a channel, frame != 0
peu605 0:b3d998305b9d 265 bmc = lastCellZero ? PREAMBLE_X : ~PREAMBLE_X;
peu605 0:b3d998305b9d 266 }
peu605 3:bdac1803f0fd 267 // lastCellZero = !(bmc & 1);
peu605 3:bdac1803f0fd 268 lastCellZero = (bmc & 1) == 0;
peu605 0:b3d998305b9d 269 *txBuffPtr++ = bmc;
peu605 0:b3d998305b9d 270
peu605 1:d7c7d1651f2e 271 // Next, 5 ~ 31 bit, audio data and VUCP bits. 28/4 = 7 loops
peu605 0:b3d998305b9d 272 // BMC encode each by lower 4 bits
peu605 0:b3d998305b9d 273 for (uint32_t i = 0; i < 7 ; ++i) {
peu605 0:b3d998305b9d 274 bmc = lastCellZero
peu605 0:b3d998305b9d 275 ? bmcTable[val & 0x0f] : ~bmcTable[val & 0x0f];
peu605 3:bdac1803f0fd 276 // lastCellZero = !(bmc & 1);
peu605 3:bdac1803f0fd 277 lastCellZero = (bmc & 1) == 0;
peu605 0:b3d998305b9d 278 *txBuffPtr++ = bmc;
peu605 0:b3d998305b9d 279 val >>= 4;
peu605 0:b3d998305b9d 280 }
peu605 0:b3d998305b9d 281
peu605 0:b3d998305b9d 282 }
peu605 0:b3d998305b9d 283
peu605 0:b3d998305b9d 284
peu605 0:b3d998305b9d 285 // consumer, copy allowed, 18bit, 32kHz
peu605 0:b3d998305b9d 286 void setChannelStatus()
peu605 0:b3d998305b9d 287 {
peu605 0:b3d998305b9d 288
peu605 0:b3d998305b9d 289 // Byte 0: General control and mode information
peu605 0:b3d998305b9d 290 // copy enable
peu605 0:b3d998305b9d 291 channelStatus[0].ltCh = _BV(C_COPY);
peu605 0:b3d998305b9d 292 channelStatus[0].rtCh = _BV(C_COPY);
peu605 0:b3d998305b9d 293
peu605 0:b3d998305b9d 294 // Byte 1: Category code
peu605 0:b3d998305b9d 295 // general
peu605 0:b3d998305b9d 296 channelStatus[1].ltCh = 0;
peu605 0:b3d998305b9d 297 channelStatus[1].rtCh = 0;
peu605 0:b3d998305b9d 298
peu605 0:b3d998305b9d 299 // Byte 2: Source and channel number
peu605 0:b3d998305b9d 300 channelStatus[2].ltCh = 0b0001 << 4;
peu605 0:b3d998305b9d 301 channelStatus[2].rtCh = 0b0010 << 4;
peu605 0:b3d998305b9d 302
peu605 0:b3d998305b9d 303 // Byte 3: Sampling frequency and clock accuracy
peu605 0:b3d998305b9d 304 channelStatus[3].ltCh = _BV(C_FS1) | _BV(C_FS0);
peu605 0:b3d998305b9d 305 channelStatus[3].rtCh = _BV(C_FS1) | _BV(C_FS0);
peu605 0:b3d998305b9d 306
peu605 11:79658b6d3f39 307 // // Byte 23: CRC
peu605 11:79658b6d3f39 308 // uint8_t *chStatusPtr = (uint8_t*) channelStatus;
peu605 11:79658b6d3f39 309 // channelStatus[23].ltCh = calcCRC(chStatusPtr);
peu605 11:79658b6d3f39 310 // ++chStatusPtr;
peu605 11:79658b6d3f39 311 // channelStatus[23].rtCh = calcCRC(chStatusPtr);
peu605 0:b3d998305b9d 312
peu605 0:b3d998305b9d 313 }
peu605 0:b3d998305b9d 314
peu605 0:b3d998305b9d 315
peu605 0:b3d998305b9d 316 uint32_t oddParity(uint32_t val)
peu605 0:b3d998305b9d 317 {
peu605 0:b3d998305b9d 318 val ^= val >> 16;
peu605 0:b3d998305b9d 319 val ^= val >> 8;
peu605 0:b3d998305b9d 320 val ^= val >> 4;
peu605 0:b3d998305b9d 321 val ^= val >> 2;
peu605 0:b3d998305b9d 322 val ^= val >> 1;
peu605 0:b3d998305b9d 323 return val & 1;
peu605 0:b3d998305b9d 324 }
peu605 0:b3d998305b9d 325
peu605 0:b3d998305b9d 326
peu605 0:b3d998305b9d 327 uint8_t calcCRC(uint8_t *chStatusPtr)
peu605 0:b3d998305b9d 328 {
peu605 0:b3d998305b9d 329 uint8_t crc = 255;
peu605 0:b3d998305b9d 330 for (uint32_t i = 0; i < 24; ++i) {
peu605 0:b3d998305b9d 331 uint8_t b = *chStatusPtr;
peu605 0:b3d998305b9d 332 for (uint32_t j = 0; j < 8; ++j) {
peu605 0:b3d998305b9d 333 if ((crc & 1) ^ (b & 1)) {
peu605 0:b3d998305b9d 334 crc >>= 1;
peu605 0:b3d998305b9d 335 crc ^= 0xb8;
peu605 0:b3d998305b9d 336 } else {
peu605 0:b3d998305b9d 337 crc >>= 1;
peu605 0:b3d998305b9d 338 }
peu605 0:b3d998305b9d 339 b >>= 1;
peu605 0:b3d998305b9d 340 }
peu605 0:b3d998305b9d 341 chStatusPtr += 2;
peu605 0:b3d998305b9d 342 }
peu605 0:b3d998305b9d 343 return crc;
peu605 0:b3d998305b9d 344 }
peu605 0:b3d998305b9d 345
peu605 0:b3d998305b9d 346
peu605 2:62c8aa0c38c7 347 #ifdef _DEBUG_CONSOLE
peu605 2:62c8aa0c38c7 348 void debugOut()
peu605 2:62c8aa0c38c7 349 {
peu605 5:1141ebe337d8 350
peu605 5:1141ebe337d8 351 char str[32];
peu605 3:bdac1803f0fd 352
peu605 8:3e913d0c7b67 353 // printf("SystemCoreClock =%d\n", SystemCoreClock);
peu605 2:62c8aa0c38c7 354
peu605 5:1141ebe337d8 355 // // dump raw data
peu605 5:1141ebe337d8 356 // uint16_t tmp = spiRxBuff[0].ltCh[6];
peu605 5:1141ebe337d8 357 // toBinary(&tmp, (char*) &str);
peu605 5:1141ebe337d8 358 // printf("Delay:%02d %s ", spiDelay, str);
peu605 5:1141ebe337d8 359 // tmp = spiRxBuff[0].ltCh[7];
peu605 5:1141ebe337d8 360 // toBinary(&tmp, (char*) &str);
peu605 5:1141ebe337d8 361 // printf("%s\n", str);
peu605 5:1141ebe337d8 362 // HAL_Delay(200);
peu605 3:bdac1803f0fd 363
peu605 3:bdac1803f0fd 364 // dump shifted data
peu605 3:bdac1803f0fd 365 int32_t val = (spiRxBuff[0].ltCh[6] << 16) | (spiRxBuff[0].ltCh[7]);
peu605 3:bdac1803f0fd 366 val >>= spiDelay;
peu605 3:bdac1803f0fd 367 uint16_t tmp = (val & 0xffff0000) >> 16;
peu605 3:bdac1803f0fd 368 toBinary(&tmp, (char*) &str);
peu605 5:1141ebe337d8 369 printf("Delay:%02d %s ", spiDelay, str);
peu605 3:bdac1803f0fd 370 tmp = val & 0xffff;
peu605 3:bdac1803f0fd 371 toBinary(&tmp, (char*) &str);
peu605 5:1141ebe337d8 372 printf("%s\n", str);
peu605 3:bdac1803f0fd 373 HAL_Delay(200);
peu605 3:bdac1803f0fd 374
peu605 5:1141ebe337d8 375 // // find loud 18bit data
peu605 5:1141ebe337d8 376 // int32_t val = (spiRxBuff[0].ltCh[6] << 16) | (spiRxBuff[0].ltCh[7]);
peu605 5:1141ebe337d8 377 // val >>= spiDelay;
peu605 5:1141ebe337d8 378 // uint16_t tmp = (val & 0xffff0000) >> 16;
peu605 5:1141ebe337d8 379 // if ((tmp & 0b1111) == 0b1110 || (tmp & 0b1111) == 0b0001) {
peu605 5:1141ebe337d8 380 // toBinary(&tmp, (char*) &str);
peu605 5:1141ebe337d8 381 // printf("Delay:%02d %s ", spiDelay, str);
peu605 5:1141ebe337d8 382 // tmp = val & 0xffff;
peu605 5:1141ebe337d8 383 // toBinary(&tmp, (char*) &str);
peu605 5:1141ebe337d8 384 // printf("%s\n", str);
peu605 5:1141ebe337d8 385 // }
peu605 3:bdac1803f0fd 386
peu605 2:62c8aa0c38c7 387 }
peu605 6:669e7d1eac35 388
peu605 6:669e7d1eac35 389
peu605 6:669e7d1eac35 390 void toBinary(uint16_t *val_ptr, char *str)
peu605 6:669e7d1eac35 391 {
peu605 6:669e7d1eac35 392 uint16_t val = *val_ptr;
peu605 6:669e7d1eac35 393 for (uint32_t j = 0; j < 16; ++j) {
peu605 6:669e7d1eac35 394 *str = val & 0x8000 ? '1' : '0';
peu605 6:669e7d1eac35 395 val <<= 1;
peu605 6:669e7d1eac35 396 ++str;
peu605 6:669e7d1eac35 397 }
peu605 6:669e7d1eac35 398 *str = '\0';
peu605 6:669e7d1eac35 399 }
peu605 2:62c8aa0c38c7 400 #endif
peu605 2:62c8aa0c38c7 401
peu605 3:bdac1803f0fd 402
peu605 2:62c8aa0c38c7 403 /**
peu605 2:62c8aa0c38c7 404 * @brief System Clock Configuration
peu605 2:62c8aa0c38c7 405 * The system Clock is configured as follow :
peu605 2:62c8aa0c38c7 406 * System Clock source = PLL (HSE)
peu605 2:62c8aa0c38c7 407 * SYSCLK(Hz) = 72000000
peu605 2:62c8aa0c38c7 408 * HCLK(Hz) = 72000000
peu605 2:62c8aa0c38c7 409 * AHB Prescaler = 1
peu605 2:62c8aa0c38c7 410 * APB1 Prescaler = 2
peu605 2:62c8aa0c38c7 411 * APB2 Prescaler = 1
peu605 2:62c8aa0c38c7 412 * HSE Frequency(Hz) = 8000000
peu605 2:62c8aa0c38c7 413 * PLLMUL = 9
peu605 2:62c8aa0c38c7 414 * Flash Latency(WS) = 2
peu605 2:62c8aa0c38c7 415 * @param None
peu605 2:62c8aa0c38c7 416 * @retval None
peu605 2:62c8aa0c38c7 417 */
peu605 2:62c8aa0c38c7 418 void SystemClock_Config(void)
peu605 2:62c8aa0c38c7 419 {
peu605 7:f3536af611e6 420
peu605 3:bdac1803f0fd 421 HAL_RCC_DeInit();
peu605 7:f3536af611e6 422 // LL_RCC_DeInit(); // not implemented yet?
peu605 2:62c8aa0c38c7 423
peu605 2:62c8aa0c38c7 424
peu605 7:f3536af611e6 425 // /* Set FLASH latency */
peu605 7:f3536af611e6 426 // LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
peu605 7:f3536af611e6 427 //
peu605 7:f3536af611e6 428 // /* Enable HSE oscillator */
peu605 7:f3536af611e6 429 // LL_RCC_HSE_Enable();
peu605 7:f3536af611e6 430 // while(LL_RCC_HSE_IsReady() != 1) {
peu605 7:f3536af611e6 431 // };
peu605 7:f3536af611e6 432 //
peu605 7:f3536af611e6 433 // /* Main PLL configuration and activation */
peu605 7:f3536af611e6 434 // LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE_DIV_1, LL_RCC_PLL_MUL_9);
peu605 7:f3536af611e6 435 //
peu605 7:f3536af611e6 436 // LL_RCC_PLL_Enable();
peu605 7:f3536af611e6 437 // while(LL_RCC_PLL_IsReady() != 1) {
peu605 7:f3536af611e6 438 // };
peu605 7:f3536af611e6 439 //
peu605 7:f3536af611e6 440 // /* Sysclk activation on the main PLL */
peu605 7:f3536af611e6 441 // LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
peu605 7:f3536af611e6 442 // LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
peu605 7:f3536af611e6 443 // while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
peu605 7:f3536af611e6 444 // };
peu605 7:f3536af611e6 445 //
peu605 7:f3536af611e6 446 // /* Set APB1 & APB2 prescaler*/
peu605 7:f3536af611e6 447 // LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
peu605 7:f3536af611e6 448 // LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
peu605 7:f3536af611e6 449 //
peu605 7:f3536af611e6 450 // /* Set systick to 1ms in using frequency set to 72MHz */
peu605 7:f3536af611e6 451 // LL_Init1msTick(72000000);
peu605 7:f3536af611e6 452 //
peu605 7:f3536af611e6 453 // /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
peu605 7:f3536af611e6 454 // LL_SetSystemCoreClock(72000000);
peu605 2:62c8aa0c38c7 455
peu605 2:62c8aa0c38c7 456
peu605 10:bbf0ab5cc56f 457 // // uint8_t SetSysClock_PLL_HSE(uint8_t bypass); in "system_clock.c", 'bypass = false' means using X'tal.
peu605 10:bbf0ab5cc56f 458 // SetSysClock_PLL_HSE(false);
peu605 10:bbf0ab5cc56f 459
peu605 10:bbf0ab5cc56f 460 RCC_OscInitTypeDef RCC_OscInitStruct;
peu605 10:bbf0ab5cc56f 461 RCC_ClkInitTypeDef RCC_ClkInitStruct;
peu605 10:bbf0ab5cc56f 462 RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInit;
peu605 10:bbf0ab5cc56f 463
peu605 10:bbf0ab5cc56f 464 /* Enable HSE oscillator and activate PLL with HSE as source */
peu605 10:bbf0ab5cc56f 465 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
peu605 10:bbf0ab5cc56f 466 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
peu605 10:bbf0ab5cc56f 467 RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
peu605 10:bbf0ab5cc56f 468 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
peu605 10:bbf0ab5cc56f 469 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
peu605 10:bbf0ab5cc56f 470 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; // 72 MHz (8 MHz * 9)
peu605 10:bbf0ab5cc56f 471 HAL_RCC_OscConfig(&RCC_OscInitStruct);
peu605 10:bbf0ab5cc56f 472
peu605 10:bbf0ab5cc56f 473 /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */
peu605 10:bbf0ab5cc56f 474 RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
peu605 10:bbf0ab5cc56f 475 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 72 MHz
peu605 10:bbf0ab5cc56f 476 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 72 MHz
peu605 10:bbf0ab5cc56f 477 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // 36 MHz
peu605 10:bbf0ab5cc56f 478 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // 72 MHz
peu605 10:bbf0ab5cc56f 479 HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
peu605 10:bbf0ab5cc56f 480
peu605 10:bbf0ab5cc56f 481 /* USB clock selection */
peu605 10:bbf0ab5cc56f 482 RCC_PeriphCLKInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
peu605 10:bbf0ab5cc56f 483 RCC_PeriphCLKInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
peu605 10:bbf0ab5cc56f 484 HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInit);
peu605 10:bbf0ab5cc56f 485
peu605 10:bbf0ab5cc56f 486
peu605 9:c2ff4ebc4327 487 // "system_stm32f1xx.h"
peu605 9:c2ff4ebc4327 488 SystemCoreClockUpdate();
peu605 9:c2ff4ebc4327 489 // I don't know HAL_Init() is needed or not.
peu605 9:c2ff4ebc4327 490 HAL_Init();
peu605 10:bbf0ab5cc56f 491
peu605 7:f3536af611e6 492 // restart uart
peu605 7:f3536af611e6 493 extern serial_t stdio_uart;
peu605 5:1141ebe337d8 494 serial_baud(&stdio_uart, 9600);
peu605 2:62c8aa0c38c7 495 }
peu605 2:62c8aa0c38c7 496
peu605 2:62c8aa0c38c7 497
peu605 0:b3d998305b9d 498 void setupPeripherals()
peu605 0:b3d998305b9d 499 {
peu605 3:bdac1803f0fd 500
peu605 0:b3d998305b9d 501 // enable GPIOB/C clock
peu605 0:b3d998305b9d 502 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
peu605 0:b3d998305b9d 503 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
peu605 0:b3d998305b9d 504
peu605 0:b3d998305b9d 505 // Configure GPIO pin : LED_Pin, PC13, OUTPUT
peu605 0:b3d998305b9d 506 LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_OUTPUT);
peu605 0:b3d998305b9d 507 LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_13, LL_GPIO_OUTPUT_PUSHPULL);
peu605 0:b3d998305b9d 508 LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 509
peu605 0:b3d998305b9d 510 // SPI IO pins
peu605 0:b3d998305b9d 511 // PB13 -> SCK, 5V tolerant
peu605 0:b3d998305b9d 512 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_13, LL_GPIO_MODE_ALTERNATE);
peu605 0:b3d998305b9d 513 LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_13, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 514 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 515 // PB14 -> MISO, 5V tolerant
peu605 0:b3d998305b9d 516 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_14, LL_GPIO_MODE_ALTERNATE);
peu605 0:b3d998305b9d 517 LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_14, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 518 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_14, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 519 // PB15 -> MOSI, 5V tolerant
peu605 0:b3d998305b9d 520 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_15, LL_GPIO_MODE_ALTERNATE);
peu605 0:b3d998305b9d 521 LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_15, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 522 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_15, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 523 // PB12 -> LRCK, 5V tolerant
peu605 0:b3d998305b9d 524 LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_12, LL_GPIO_MODE_INPUT);
peu605 0:b3d998305b9d 525 // LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_12, LL_GPIO_PULL_DOWN);
peu605 0:b3d998305b9d 526 LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_12, LL_GPIO_SPEED_FREQ_MEDIUM);
peu605 0:b3d998305b9d 527
peu605 0:b3d998305b9d 528 // SPI Slave full duplex, mode 0, 16bit
peu605 0:b3d998305b9d 529 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); // SPI2
peu605 0:b3d998305b9d 530 LL_SPI_SetMode(_SPI, LL_SPI_MODE_SLAVE);
peu605 0:b3d998305b9d 531 LL_SPI_SetTransferDirection(_SPI,LL_SPI_FULL_DUPLEX);
peu605 0:b3d998305b9d 532 LL_SPI_SetClockPhase(_SPI, LL_SPI_PHASE_1EDGE);
peu605 0:b3d998305b9d 533 LL_SPI_SetClockPolarity(_SPI, LL_SPI_POLARITY_LOW);
peu605 0:b3d998305b9d 534 LL_SPI_SetTransferBitOrder(_SPI, LL_SPI_MSB_FIRST);
peu605 0:b3d998305b9d 535 LL_SPI_SetDataWidth(_SPI, LL_SPI_DATAWIDTH_16BIT);
peu605 0:b3d998305b9d 536 LL_SPI_SetNSSMode(_SPI, LL_SPI_NSS_SOFT);
peu605 0:b3d998305b9d 537
peu605 0:b3d998305b9d 538 // connect to DMAReq
peu605 0:b3d998305b9d 539 LL_SPI_EnableDMAReq_RX(_SPI);
peu605 0:b3d998305b9d 540 LL_SPI_EnableDMAReq_TX(_SPI);
peu605 0:b3d998305b9d 541
peu605 0:b3d998305b9d 542
peu605 0:b3d998305b9d 543 // DMA
peu605 0:b3d998305b9d 544 LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); // DMA1
peu605 0:b3d998305b9d 545 // _SPIRxDMA, DMA1 Channel 4
peu605 0:b3d998305b9d 546 LL_DMA_ConfigTransfer(_SPIRxDMA, _SPIRxDMACh,
peu605 0:b3d998305b9d 547 LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_CIRCULAR |
peu605 0:b3d998305b9d 548 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
peu605 0:b3d998305b9d 549 LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD);
peu605 0:b3d998305b9d 550 LL_DMA_ConfigAddresses(_SPIRxDMA, _SPIRxDMACh,
peu605 0:b3d998305b9d 551 (uint32_t)&(_SPI->DR), (uint32_t)&spiRxBuff,
peu605 0:b3d998305b9d 552 LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
peu605 0:b3d998305b9d 553 LL_DMA_SetDataLength(_SPIRxDMA, _SPIRxDMACh, DMA_TRANSFER_LENGTH);
peu605 0:b3d998305b9d 554
peu605 0:b3d998305b9d 555 // _SPITxDMA, DMA1 Channel5
peu605 0:b3d998305b9d 556 LL_DMA_ConfigTransfer(_SPITxDMA, _SPITxDMACh,
peu605 0:b3d998305b9d 557 LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_MEDIUM | LL_DMA_MODE_CIRCULAR |
peu605 0:b3d998305b9d 558 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
peu605 0:b3d998305b9d 559 LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD);
peu605 0:b3d998305b9d 560 LL_DMA_ConfigAddresses(_SPITxDMA, _SPITxDMACh,
peu605 0:b3d998305b9d 561 (uint32_t)&spiTxBuff, (uint32_t)&(_SPI->DR),
peu605 0:b3d998305b9d 562 LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
peu605 0:b3d998305b9d 563 LL_DMA_SetDataLength(_SPITxDMA, _SPITxDMACh, DMA_TRANSFER_LENGTH);
peu605 0:b3d998305b9d 564
peu605 0:b3d998305b9d 565 // Enable SPIRx DMA IRQ, Half Transfer and Transfer Complete
peu605 0:b3d998305b9d 566 NVIC_SetPriority(_SPIRxDMAIRQn, 0);
peu605 0:b3d998305b9d 567 NVIC_EnableIRQ(_SPIRxDMAIRQn);
peu605 0:b3d998305b9d 568
peu605 0:b3d998305b9d 569 LL_DMA_EnableIT_TC(_SPIRxDMA, _SPIRxDMACh);
peu605 0:b3d998305b9d 570 LL_DMA_EnableIT_HT(_SPIRxDMA, _SPIRxDMACh);
peu605 0:b3d998305b9d 571
peu605 0:b3d998305b9d 572 // Enable DMA Channel
peu605 0:b3d998305b9d 573 LL_DMA_EnableChannel(_SPIRxDMA, _SPIRxDMACh);
peu605 0:b3d998305b9d 574 LL_DMA_EnableChannel(_SPITxDMA, _SPITxDMACh);
peu605 0:b3d998305b9d 575
peu605 0:b3d998305b9d 576 }
peu605 4:c7c69c9b3cac 577
peu605 4:c7c69c9b3cac 578 /*
peu605 4:c7c69c9b3cac 579 // Use java to create BMC table, because I am a javaer.
peu605 4:c7c69c9b3cac 580
peu605 4:c7c69c9b3cac 581 private void start() {
peu605 4:c7c69c9b3cac 582 StringBuilder sb = new StringBuilder();
peu605 4:c7c69c9b3cac 583 for (char i = 0; i < 16; ++i) {
peu605 4:c7c69c9b3cac 584 sb.append(String.format("%02d", (int) i)).append(" = 0b");
peu605 4:c7c69c9b3cac 585 boolean lastCellZero = true;
peu605 4:c7c69c9b3cac 586 char c = i;
peu605 4:c7c69c9b3cac 587 for (int j = 0; j < 4; ++j) {
peu605 4:c7c69c9b3cac 588 if ((c & 1) == 0) {
peu605 4:c7c69c9b3cac 589 if (lastCellZero) {
peu605 4:c7c69c9b3cac 590 sb.append("1111");
peu605 4:c7c69c9b3cac 591 lastCellZero = false;
peu605 4:c7c69c9b3cac 592 } else {
peu605 4:c7c69c9b3cac 593 sb.append("0000");
peu605 4:c7c69c9b3cac 594 lastCellZero = true;
peu605 4:c7c69c9b3cac 595 }
peu605 4:c7c69c9b3cac 596 } else {
peu605 4:c7c69c9b3cac 597 if (lastCellZero) {
peu605 4:c7c69c9b3cac 598 sb.append("1100");
peu605 4:c7c69c9b3cac 599 lastCellZero = true;
peu605 4:c7c69c9b3cac 600 } else {
peu605 4:c7c69c9b3cac 601 sb.append("0011");
peu605 4:c7c69c9b3cac 602 lastCellZero = false;
peu605 4:c7c69c9b3cac 603 }
peu605 4:c7c69c9b3cac 604 }
peu605 4:c7c69c9b3cac 605 c >>= 1;
peu605 4:c7c69c9b3cac 606 }
peu605 4:c7c69c9b3cac 607 sb.append('\n');
peu605 4:c7c69c9b3cac 608 }
peu605 4:c7c69c9b3cac 609 System.out.println(sb.toString());
peu605 4:c7c69c9b3cac 610 }
peu605 4:c7c69c9b3cac 611 */