94 static const int32_t DEFAULT_FREQUENCY = 100000;
104 static SPI defaultInstance;
105 return defaultInstance;
120 const Pin::Mask sclk = Pin::Mask::NULL_PIN,
const uint32_t frequency = DEFAULT_FREQUENCY,
142 SPI::reset_pin_mask(this->m_mosi, mask);
149 SPI::reset_pin_mask(this->m_miso, mask);
157 SPI::reset_pin_mask(this->m_sclk, mask);
169 if (0x02U &
static_cast<unsigned int>(mode))
172 this->m_sclk.
clear();
182 this->m_bitmode = bitmode;
193 PropWare::ErrorCode
set_clock (
const uint32_t frequency) {
194 const uint32_t MAX_CLOCK =
CLKFREQ / 20;
195 if (MAX_CLOCK < frequency)
198 this->m_clkDelay = (
CLKFREQ / frequency) >> 1U;
209 return CLKFREQ / (this->m_clkDelay << 1U);
225 switch (this->m_bitmode) {
226 case BitMode::MSB_FIRST:
227 this->shift_out_msb_first(bits, value);
229 case BitMode::LSB_FIRST:
230 this->shift_out_lsb_first(bits, value);
242 uint32_t
shift_in (
const unsigned int bits)
const {
243 const bool clockPhase =
static_cast<bool>(
static_cast<unsigned int>(this->m_mode) & 0x01U);
245 switch (this->m_bitmode) {
246 case BitMode::MSB_FIRST:
247 return this->shift_in_msb_phs1(bits);
248 case BitMode::LSB_FIRST:
249 return this->shift_in_lsb_phs1(bits);
252 switch (this->m_bitmode) {
253 case BitMode::MSB_FIRST:
254 return this->shift_in_msb_phs0(bits);
255 case BitMode::LSB_FIRST:
256 return this->shift_in_lsb_phs0(bits);
272 #define ASMVAR(name) FC_ADDR(#name "%=", "SpiBlockWriteStart%=")
273 FC_START(
"SpiBlockWriteStart%=",
"SpiBlockWriteEnd%=")
274 " jmp #" FC_ADDR(
"loopOverBytes%=",
"SpiBlockWriteStart%=")
" \n\t"
283 "loopOverBytes%=: \n\t"
284 " rdbyte " ASMVAR(data)
", %[_bufAdr] \n\t"
285 " mov " ASMVAR(bitIdx)
", #8 \n\t"
286 " ror " ASMVAR(data)
", " ASMVAR(bitIdx)
" \n\t"
288 "loopOverBits%=: \n\t"
289 " rol " ASMVAR(data)
", #1 wc \n\t"
290 " muxc outa, %[_mosi] \n\t"
291 " xor outa, %[_sclk] \n\t"
292 " xor outa, %[_sclk] \n\t"
293 " djnz " ASMVAR(bitIdx)
", #" FC_ADDR(
"loopOverBits%=",
"SpiBlockWriteStart%=")
" \n\t"
296 " add %[_bufAdr], #1 \n\t"
298 " djnz %[_numberOfBytes], #" FC_ADDR(
"loopOverBytes%=",
"SpiBlockWriteStart%=")
" \n\t"
300 " or outa, %[_mosi] \n\t"
301 FC_END(
"SpiBlockWriteEnd%=")
303 : [_bufAdr]
"+r"(buffer),
304 [_numberOfBytes]
"+r"(numberOfBytes)
305 :[_mosi]
"r"(this->m_mosi.get_mask()),
306 [_sclk]
"r"(this->m_sclk.get_mask())
319 #define ASMVAR(name) FC_ADDR(#name "%=", "SpiBlockReadStart%=")
320 FC_START(
"SpiBlockReadStart%=",
"SpiBlockReadEnd%=")
321 " jmp #" FC_ADDR(
"outerLoop%=",
"SpiBlockReadStart%=")
" \n\t"
331 " mov " ASMVAR(data)
", #0 \n\t"
332 " mov " ASMVAR(bitIdx)
", #8 \n\t"
335 " test %[_miso], ina wc \n\t"
336 " xor outa, %[_sclk] \n\t"
337 " rcl " ASMVAR(data)
", #1 \n\t"
338 " xor outa, %[_sclk] \n\t"
339 " djnz " ASMVAR(bitIdx)
", #" FC_ADDR(
"loop%=",
"SpiBlockReadStart%=")
" \n\t"
342 " wrbyte " ASMVAR(data)
", %[_bufAdr] \n\t"
343 " add %[_bufAdr], #1 \n\t"
345 " djnz %[_numberOfBytes], #" FC_ADDR(
"outerLoop%=",
"SpiBlockReadStart%=")
" \n\t"
346 FC_END(
"SpiBlockReadEnd%=")
347 : [_bufAdr]
"+r"(buffer),
348 [_numberOfBytes]
"+r"(numberOfBytes)
349 :[_miso]
"r"(this->m_miso.get_mask()),
350 [_sclk]
"r"(this->m_sclk.get_mask())
359 virtual void puts (
const char string[]) {
360 char *sPtr = (
char *)
string;
377 const char str[] =
"SPI Error ";
382 printer << str << relativeErr <<
": Frequency set too high";
387 printer <<
"Unknown SPI error " << relativeErr <<
'\n';
389 printer <<
"Unknown error " << err <<
'\n';
395 void shift_out_msb_first (uint32_t bits, uint32_t data)
const {
396 #pragma GCC diagnostic push
397 #pragma GCC diagnostic ignored "-Wuninitialized"
400 FC_START(
"SpiSendMsbFirstStart%=",
"SpiSendMsbFirstEnd%=")
401 " ror %[_data], %[_bitCount] \n\t"
402 " mov %[_clock], %[_clkDelay] \n\t"
403 " add %[_clock], CNT \n\t"
406 " rol %[_data], #1 wc \n\t"
407 " muxc outa, %[_mosi] \n\t"
408 " waitcnt %[_clock], %[_clkDelay] \n\t"
409 " xor outa, %[_sclk] \n\t"
410 " waitcnt %[_clock], %[_clkDelay] \n\t"
411 " xor outa, %[_sclk] \n\t"
412 " djnz %[_bitCount], #" FC_ADDR(
"loop%=",
"SpiSendMsbFirstStart%=")
" \n\t"
414 " or outa, %[_mosi] \n\t"
415 FC_END(
"SpiSendMsbFirstEnd%=")
416 : [_bitCount]
"+r"(bits),
419 : [_mosi]
"r"(this->m_mosi.get_mask()),
420 [_sclk]
"r"(this->m_sclk.get_mask()),
421 [_clkDelay]
"r"(this->m_clkDelay)
423 #pragma GCC diagnostic pop
426 void shift_out_lsb_first (uint32_t bits, uint32_t data)
const {
427 #pragma GCC diagnostic push
428 #pragma GCC diagnostic ignored "-Wuninitialized"
431 FC_START(
"SpiSendLsbFirstStart%=",
"SpiSendLsbFirstEnd%=")
433 " mov %[_clock], CNT \n\t"
434 " add %[_clock], %[_clkDelay] \n\t"
437 " ror %[_data], #1 wc '' move LSB into carry \n\t"
438 " muxc OUTA, %[_mosi] \n\t"
439 " waitcnt %[_clock], %[_clkDelay] \n\t"
440 " xor OUTA, %[_sclk] \n\t"
441 " waitcnt %[_clock], %[_clkDelay] \n\t"
442 " xor OUTA, %[_sclk] \n\t"
443 " djnz %[_bitCount], #" FC_ADDR(
"loop%=",
"SpiSendLsbFirstStart%=")
" \n\t"
445 " or outa, %[_mosi] \n\t"
446 FC_END(
"SpiSendLsbFirstEnd%=")
447 : [_bitCount]
"+r"(bits),
450 : [_mosi]
"r"(this->m_mosi.get_mask()),
451 [_sclk]
"r"(this->m_sclk.get_mask()),
452 [_clkDelay]
"r"(this->m_clkDelay)
454 #pragma GCC diagnostic pop
457 uint32_t shift_in_msb_phs0 (
unsigned int bits)
const {
458 #pragma GCC diagnostic push
459 #pragma GCC diagnostic ignored "-Wuninitialized"
461 unsigned int tempData;
463 FC_START(
"SpiReadMsbPhs0Start%=",
"SpiReadMsbPhs0End%=")
464 " ror %[_data], %[_bitCount] '' move MSB into bit 31 \n\t"
465 " mov %[_clock], %[_clkDelay] \n\t"
466 " add %[_clock], CNT \n\t"
469 " test %[_miso], ina wc \n\t"
470 " waitcnt %[_clock], %[_clkDelay] \n\t"
471 " xor outa, %[_sclk] \n\t"
472 " rcl %[_data], #1 \n\t"
473 " waitcnt %[_clock], %[_clkDelay] \n\t"
474 " xor outa, %[_sclk] \n\t"
475 " djnz %[_bitCount], #" FC_ADDR(
"loop%=",
"SpiReadMsbPhs0Start%=")
" \n\t"
476 FC_END(
"SpiReadMsbPhs0End%=")
477 : [_bitCount]
"+r"(bits),
478 [_clock]
"+r"(clock),
479 [_data]
"+r"(tempData)
480 :[_miso]
"r"(this->m_miso.get_mask()),
481 [_sclk]
"r"(this->m_sclk.get_mask()),
482 [_clkDelay]
"r"(this->m_clkDelay)
484 #pragma GCC diagnostic pop
488 uint32_t shift_in_lsb_phs0 (
const unsigned int bits)
const {
489 #pragma GCC diagnostic push
490 #pragma GCC diagnostic ignored "-Wuninitialized"
492 unsigned int tempData;
493 unsigned int modifiableBits = bits;
495 FC_START(
"SpiReadLsbPhs0Start%=",
"SpiReadLsbPhs0End%=")
496 " ror %[_data], %[_bitCount] '' move MSB into bit 31 \n\t"
497 " mov %[_clock], %[_clkDelay] \n\t"
498 " add %[_clock], CNT \n\t"
501 " test %[_miso], ina wc \n\t"
502 " waitcnt %[_clock], %[_clkDelay] \n\t"
503 " xor outa, %[_sclk] \n\t"
504 " rcr %[_data], #1 \n\t"
505 " waitcnt %[_clock], %[_clkDelay] \n\t"
506 " xor outa, %[_sclk] \n\t"
507 " djnz %[_bitCount], #" FC_ADDR(
"loop%=",
"SpiReadLsbPhs0Start%=")
" \n\t"
508 FC_END(
"SpiReadLsbPhs0End%=")
509 : [_bitCount]
"+r"(modifiableBits),
510 [_clock]
"+r"(clock),
511 [_data]
"+r"(tempData)
512 :[_miso]
"r"(this->m_miso.get_mask()),
513 [_sclk]
"r"(this->m_sclk.get_mask()),
514 [_clkDelay]
"r"(this->m_clkDelay)
516 #pragma GCC diagnostic pop
520 uint32_t shift_in_msb_phs1 (
unsigned int bits)
const {
521 #pragma GCC diagnostic push
522 #pragma GCC diagnostic ignored "-Wuninitialized"
524 unsigned int tempData;
526 FC_START(
"SpiReadMsbPhs1Start%=",
"SpiReadMsbPhs1End%=")
527 " ror %[_data], %[_bitCount] '' move MSB into bit 31 \n\t"
528 " mov %[_clock], %[_clkDelay] \n\t"
529 " add %[_clock], CNT \n\t"
532 " xor outa, %[_sclk] \n\t"
533 " waitcnt %[_clock], %[_clkDelay] \n\t"
534 " test %[_miso], ina wc \n\t"
535 " xor outa, %[_sclk] \n\t"
536 " waitcnt %[_clock], %[_clkDelay] \n\t"
537 " rcl %[_data], #1 \n\t"
538 " djnz %[_bitCount], #" FC_ADDR(
"loop%=",
"SpiReadMsbPhs1Start%=")
" \n\t"
539 FC_END(
"SpiReadMsbPhs1End%=")
540 : [_bitCount]
"+r"(bits),
541 [_clock]
"+r"(clock),
542 [_data]
"+r"(tempData)
543 :[_miso]
"r"(this->m_miso.get_mask()),
544 [_sclk]
"r"(this->m_sclk.get_mask()),
545 [_clkDelay]
"r"(this->m_clkDelay)
547 #pragma GCC diagnostic pop
551 uint32_t shift_in_lsb_phs1 (
unsigned int bits)
const {
552 #pragma GCC diagnostic push
553 #pragma GCC diagnostic ignored "-Wuninitialized"
555 unsigned int tempData;
557 FC_START(
"SpiReadLsbPhs1Start%=",
"SpiReadLsbPhs1End%=")
558 " ror %[_data], %[_bitCount] '' move MSB into bit 31 \n\t"
559 " mov %[_clock], %[_clkDelay] \n\t"
560 " add %[_clock], CNT \n\t"
563 " xor outa, %[_sclk] \n\t"
564 " waitcnt %[_clock], %[_clkDelay] \n\t"
565 " test %[_miso], ina wc \n\t"
566 " xor outa, %[_sclk] \n\t"
567 " waitcnt %[_clock], %[_clkDelay] \n\t"
568 " rcr %[_data], #1 \n\t"
569 " djnz %[_bitCount], #" FC_ADDR(
"loop%=",
"SpiReadLsbPhs1Start%=")
" \n\t"
570 FC_END(
"SpiReadLsbPhs1End%=")
571 : [_bitCount]
"+r"(bits),
572 [_clock]
"+r"(clock),
573 [_data]
"+r"(tempData)
574 :[_miso]
"r"(this->m_miso.get_mask()),
575 [_sclk]
"r"(this->m_sclk.get_mask()),
576 [_clkDelay]
"r"(this->m_clkDelay)
578 #pragma GCC diagnostic pop
584 static void reset_pin_mask (Pin &pin,
const Port::Mask mask) {
595 unsigned int m_clkDelay;