95 static const int32_t DEFAULT_FREQUENCY = 100000;
105 static SPI defaultInstance;
106 return &defaultInstance;
122 const Mode mode =
MODE_0,
const BitMode bitmode = MSB_FIRST)
123 : m_bitmode(bitmode) {
142 this->reset_pin_mask(this->m_mosi, mask);
149 this->reset_pin_mask(this->m_miso, mask);
157 this->reset_pin_mask(this->m_sclk, mask);
174 this->m_sclk.
clear();
186 this->m_bitmode = bitmode;
197 PropWare::ErrorCode
set_clock (
const int32_t frequency) {
198 static const int32_t MAX_CLOCK = CLKFREQ / 80;
199 if (MAX_CLOCK <= frequency || 0 > frequency)
201 this->m_clkDelay = (CLKFREQ / frequency) >> 1;
211 return CLKFREQ / (this->m_clkDelay << 1);
227 switch (this->m_bitmode) {
229 this->shift_out_msb_first(bits, value);
232 this->shift_out_lsb_first(bits, value);
244 uint32_t
shift_in (
const unsigned int bits)
const {
245 const bool clockPhase = this->m_mode & 0x01;
247 switch (this->m_bitmode) {
249 return this->shift_in_msb_phs1(bits);
251 return this->shift_in_lsb_phs1(bits);
254 switch (this->m_bitmode) {
256 return this->shift_in_msb_phs0(bits);
258 return this->shift_in_lsb_phs0(bits);
261 return (uint32_t) -1;
272 #define ASMVAR(name) "__LMM_FCACHE_START+(" #name "%= - SpiBlockWriteStart%=)" 274 " fcache #(SpiBlockWriteEnd%= - SpiBlockWriteStart%=) \n\t" 275 " .compress off \n\t" 277 "SpiBlockWriteStart%=: \n\t" 278 " jmp #__LMM_FCACHE_START+(outerLoop%= - SpiBlockWriteStart%=) \n\t" 288 " rdbyte " ASMVAR(data)
", %[_bufAdr] \n\t" 289 " mov " ASMVAR(bitIdx)
", #8 \n\t" 290 " ror " ASMVAR(data)
", " ASMVAR(bitIdx)
" \n\t" 293 " rol " ASMVAR(data)
", #1 wc \n\t" 294 " muxc outa, %[_mosi] \n\t" 295 " xor outa, %[_sclk] \n\t" 296 " xor outa, %[_sclk] \n\t" 297 " djnz " ASMVAR(bitIdx)
", #__LMM_FCACHE_START+(loop%= - SpiBlockWriteStart%=) \n\t" 300 " add %[_bufAdr], #1 \n\t" 302 " djnz %[_numberOfBytes], #__LMM_FCACHE_START+(outerLoop%= - SpiBlockWriteStart%=) \n\t" 304 " or outa, %[_mosi] \n\t" 305 " jmp __LMM_RET \n\t" 306 "SpiBlockWriteEnd%=: \n\t" 307 " .compress default \n\t" 308 : [_bufAdr]
"+r"(buffer),
309 [_numberOfBytes]
"+r"(numberOfBytes)
310 :[_mosi]
"r"(this->m_mosi.get_mask()),
311 [_sclk]
"r"(this->m_sclk.get_mask())
324 #pragma GCC diagnostic push 325 #pragma GCC diagnostic ignored "-Wuninitialized" 326 #define ASMVAR(name) "__LMM_FCACHE_START+(" #name "%= - SpiBlockReadStart%=)" 328 " fcache #(SpiBlockReadEnd%= - SpiBlockReadStart%=) \n\t" 329 " .compress off \n\t" 331 "SpiBlockReadStart%=: \n\t" 332 " jmp #__LMM_FCACHE_START+(outerLoop%= - SpiBlockReadStart%=) \n\t" 342 " mov " ASMVAR(data)
", #0 \n\t" 343 " mov " ASMVAR(bitIdx)
", #8 \n\t" 346 " test %[_miso], ina wc \n\t" 347 " xor outa, %[_sclk] \n\t" 348 " rcl " ASMVAR(data)
", #1 \n\t" 349 " xor outa, %[_sclk] \n\t" 350 " djnz " ASMVAR(bitIdx)
", #__LMM_FCACHE_START+(loop%= - SpiBlockReadStart%=) \n\t" 353 " wrbyte " ASMVAR(data)
", %[_bufAdr] \n\t" 354 " add %[_bufAdr], #1 \n\t" 356 " djnz %[_numberOfBytes], #__LMM_FCACHE_START+(outerLoop%= - SpiBlockReadStart%=) \n\t" 358 " jmp __LMM_RET \n\t" 359 "SpiBlockReadEnd%=: \n\t" 360 " .compress default \n\t" 361 : [_bufAdr]
"+r"(buffer),
362 [_numberOfBytes]
"+r"(numberOfBytes)
363 :[_miso]
"r"(this->m_miso.get_mask()),
364 [_sclk]
"r"(this->m_sclk.get_mask())
367 #pragma GCC diagnostic pop 374 void puts (
const char string[]) {
375 char *sPtr = (
char *)
string;
392 const char str[] =
"SPI Error ";
397 *printer << str << relativeErr <<
": Frequency set too high";
401 if (err > BEG_ERROR && err < (BEG_ERROR +
END_ERROR))
402 *printer <<
"Unknown SPI error " << relativeErr <<
'\n';
404 *printer <<
"Unknown error " << err <<
'\n';
410 void shift_out_msb_first (uint32_t bits, uint32_t data)
const {
411 #pragma GCC diagnostic push 412 #pragma GCC diagnostic ignored "-Wuninitialized" 415 " fcache #(SpiSendMsbFirstEnd%= - SpiSendMsbFirstStart%=) \n\t" 416 " .compress off \n\t" 417 "SpiSendMsbFirstStart%=: \n\t" 419 " ror %[_data], %[_bitCount] \n\t" 420 " mov %[_clock], %[_clkDelay] \n\t" 421 " add %[_clock], CNT \n\t" 424 " rol %[_data], #1 wc \n\t" 425 " muxc outa, %[_mosi] \n\t" 426 " waitcnt %[_clock], %[_clkDelay] \n\t" 427 " xor outa, %[_sclk] \n\t" 428 " waitcnt %[_clock], %[_clkDelay] \n\t" 429 " xor outa, %[_sclk] \n\t" 430 " djnz %[_bitCount], #__LMM_FCACHE_START+(loop%= - SpiSendMsbFirstStart%=) \n\t" 432 " or outa, %[_mosi] \n\t" 433 " jmp __LMM_RET \n\t" 434 "SpiSendMsbFirstEnd%=: \n\t" 435 " .compress default \n\t" 436 : [_bitCount]
"+r"(bits),
439 : [_mosi]
"r"(this->m_mosi.get_mask()),
440 [_sclk]
"r"(this->m_sclk.get_mask()),
441 [_clkDelay]
"r"(this->m_clkDelay)
443 #pragma GCC diagnostic pop 446 void shift_out_lsb_first (uint32_t bits, uint32_t data)
const {
447 #pragma GCC diagnostic push 448 #pragma GCC diagnostic ignored "-Wuninitialized" 451 " fcache #(SpiSendLsbFirstEnd%= - SpiSendLsbFirstStart%=) \n\t" 452 " .compress off \n\t" 454 "SpiSendLsbFirstStart%=: \n\t" 456 " mov %[_clock], CNT \n\t" 457 " add %[_clock], %[_clkDelay] \n\t" 460 " ror %[_data], #1 wc '' move LSB into carry \n\t" 461 " muxc OUTA, %[_mosi] \n\t" 462 " waitcnt %[_clock], %[_clkDelay] \n\t" 463 " xor OUTA, %[_sclk] \n\t" 464 " waitcnt %[_clock], %[_clkDelay] \n\t" 465 " xor OUTA, %[_sclk] \n\t" 466 " djnz %[_bitCount], #__LMM_FCACHE_START+(loop%= - SpiSendLsbFirstStart%=) \n\t" 468 " or outa, %[_mosi] \n\t" 469 " jmp __LMM_RET \n\t" 471 "SpiSendLsbFirstEnd%=: \n\t" 472 " .compress default \n\t" 473 : [_bitCount]
"+r"(bits),
476 : [_mosi]
"r"(this->m_mosi.get_mask()),
477 [_sclk]
"r"(this->m_sclk.get_mask()),
478 [_clkDelay]
"r"(this->m_clkDelay)
480 #pragma GCC diagnostic pop 483 uint32_t shift_in_msb_phs0 (
unsigned int bits)
const {
484 #pragma GCC diagnostic push 485 #pragma GCC diagnostic ignored "-Wuninitialized" 487 unsigned int tempData;
489 " fcache #(SpiReadMsbPhs0End%= - SpiReadMsbPhs0Start%=) \n\t" 490 " .compress off \n\t" 492 "SpiReadMsbPhs0Start%=: \n\t" 493 " ror %[_data], %[_bitCount] '' move MSB into bit 31 \n\t" 494 " mov %[_clock], %[_clkDelay] \n\t" 495 " add %[_clock], CNT \n\t" 498 " test %[_miso], ina wc \n\t" 499 " waitcnt %[_clock], %[_clkDelay] \n\t" 500 " xor outa, %[_sclk] \n\t" 501 " rcl %[_data], #1 \n\t" 502 " waitcnt %[_clock], %[_clkDelay] \n\t" 503 " xor outa, %[_sclk] \n\t" 504 " djnz %[_bitCount], #__LMM_FCACHE_START+(loop%= - SpiReadMsbPhs0Start%=) \n\t" 506 " jmp __LMM_RET \n\t" 507 "SpiReadMsbPhs0End%=: \n\t" 508 " .compress default \n\t" 509 : [_bitCount]
"+r"(bits),
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_lsb_phs0 (
const unsigned int bits)
const {
521 #pragma GCC diagnostic push 522 #pragma GCC diagnostic ignored "-Wuninitialized" 524 unsigned int tempData;
525 unsigned int modifiableBits = bits;
527 " fcache #(SpiReadLsbPhs0End%= - SpiReadLsbPhs0Start%=) \n\t" 528 " .compress off \n\t" 530 "SpiReadLsbPhs0Start%=: \n\t" 531 " ror %[_data], %[_bitCount] '' move MSB into bit 31 \n\t" 532 " mov %[_clock], %[_clkDelay] \n\t" 533 " add %[_clock], CNT \n\t" 536 " test %[_miso], ina wc \n\t" 537 " waitcnt %[_clock], %[_clkDelay] \n\t" 538 " xor outa, %[_sclk] \n\t" 539 " rcr %[_data], #1 \n\t" 540 " waitcnt %[_clock], %[_clkDelay] \n\t" 541 " xor outa, %[_sclk] \n\t" 542 " djnz %[_bitCount], #__LMM_FCACHE_START+(loop%= - SpiReadLsbPhs0Start%=) \n\t" 544 " jmp __LMM_RET \n\t" 545 "SpiReadLsbPhs0End%=: \n\t" 546 " .compress default \n\t" 547 : [_bitCount]
"+r"(modifiableBits),
548 [_clock]
"+r"(clock),
549 [_data]
"+r"(tempData)
550 :[_miso]
"r"(this->m_miso.get_mask()),
551 [_sclk]
"r"(this->m_sclk.get_mask()),
552 [_clkDelay]
"r"(this->m_clkDelay)
554 #pragma GCC diagnostic pop 558 uint32_t shift_in_msb_phs1 (
unsigned int bits)
const {
559 #pragma GCC diagnostic push 560 #pragma GCC diagnostic ignored "-Wuninitialized" 562 unsigned int tempData;
564 " fcache #(SpiReadMsbPhs1End%= - SpiReadMsbPhs1Start%=) \n\t" 565 " .compress off \n\t" 567 "SpiReadMsbPhs1Start%=: \n\t" 568 " ror %[_data], %[_bitCount] '' move MSB into bit 31 \n\t" 569 " mov %[_clock], %[_clkDelay] \n\t" 570 " add %[_clock], CNT \n\t" 573 " xor outa, %[_sclk] \n\t" 574 " waitcnt %[_clock], %[_clkDelay] \n\t" 575 " test %[_miso], ina wc \n\t" 576 " xor outa, %[_sclk] \n\t" 577 " waitcnt %[_clock], %[_clkDelay] \n\t" 578 " rcl %[_data], #1 \n\t" 579 " djnz %[_bitCount], #__LMM_FCACHE_START+(loop%= - SpiReadMsbPhs1Start%=) \n\t" 581 " jmp __LMM_RET \n\t" 582 "SpiReadMsbPhs1End%=: \n\t" 583 " .compress default \n\t" 584 : [_bitCount]
"+r"(bits),
585 [_clock]
"+r"(clock),
586 [_data]
"+r"(tempData)
587 :[_miso]
"r"(this->m_miso.get_mask()),
588 [_sclk]
"r"(this->m_sclk.get_mask()),
589 [_clkDelay]
"r"(this->m_clkDelay)
591 #pragma GCC diagnostic pop 595 uint32_t shift_in_lsb_phs1 (
unsigned int bits)
const {
596 #pragma GCC diagnostic push 597 #pragma GCC diagnostic ignored "-Wuninitialized" 599 unsigned int tempData;
601 " fcache #(SpiReadLsbPhs1End%= - SpiReadLsbPhs1Start%=) \n\t" 602 " .compress off \n\t" 604 "SpiReadLsbPhs1Start%=: \n\t" 605 " ror %[_data], %[_bitCount] '' move MSB into bit 31 \n\t" 606 " mov %[_clock], %[_clkDelay] \n\t" 607 " add %[_clock], CNT \n\t" 610 " xor outa, %[_sclk] \n\t" 611 " waitcnt %[_clock], %[_clkDelay] \n\t" 612 " test %[_miso], ina wc \n\t" 613 " xor outa, %[_sclk] \n\t" 614 " waitcnt %[_clock], %[_clkDelay] \n\t" 615 " rcr %[_data], #1 \n\t" 616 " djnz %[_bitCount], #__LMM_FCACHE_START+(loop%= - SpiReadLsbPhs1Start%=) \n\t" 618 " jmp __LMM_RET \n\t" 619 "SpiReadLsbPhs1End%=: \n\t" 620 " .compress default \n\t" 621 : [_bitCount]
"+r"(bits),
622 [_clock]
"+r"(clock),
623 [_data]
"+r"(tempData)
624 :[_miso]
"r"(this->m_miso.get_mask()),
625 [_sclk]
"r"(this->m_sclk.get_mask()),
626 [_clkDelay]
"r"(this->m_clkDelay)
628 #pragma GCC diagnostic pop 634 static void reset_pin_mask (
Pin &pin,
const Port::Mask mask) {
645 unsigned int m_clkDelay;
void set_mask(const PropWare::Port::Mask mask)
Utility class to handle general purpose I/O pins.
Interface for all classes capable of printing.
SPI(const Port::Mask mosi=PropWare::Port::NULL_PIN, const Port::Mask miso=PropWare::Port::NULL_PIN, const Port::Mask sclk=PropWare::Port::NULL_PIN, const int32_t frequency=DEFAULT_FREQUENCY, const Mode mode=MODE_0, const BitMode bitmode=MSB_FIRST)
Construct an SPI bus on the given pins with the given settings.
void set_dir_in() const
Set the port for input.
void puts(const char string[])
Send a null-terminated character array. Though this method could be created using put_char...
void clear() const
Clear selected output port (set it to 0)
Generic definitions and functions for the Parallax Propeller.
PropWare::ErrorCode set_clock(const int32_t frequency)
Change the SPI module's clock frequency.
char get_char()
Read and return a single character. Whether the method is blocking or not depends entirely on the imp...
void set_mosi(const Port::Mask mask)
Release the current MOSI pin as a floating input and set the new one as output.
void shift_out_block_msb_first_fast(const uint8_t buffer[], size_t numberOfBytes)
Receive an array of data at max transmit speed. Mode is always MODE_0 and data is always MSB first...
void print_error_str(const Printer *printer, const ErrorCode err) const
Print through UART an error string followed by entering an infinite loop.
void shift_in_block_mode0_msb_first_fast(uint8_t *buffer, size_t numberOfBytes)
Receive an array of data at max transmit speed. Mode is always MODE_0 and data is always MSB first...
void shift_out(uint8_t bits, uint32_t value) const
Send a value out to a peripheral device.
Mode
Descriptor for SPI signal as defined by Motorola modes.
Container class that has formatting methods for human-readable output. This class can be constructed ...
void set_dir_out() const
Set the port for output.
void put_char(const char c)
Print a single character.
~SPI()
Release the pins to floating inputs.
void set_bit_mode(const BitMode bitmode)
Set the bitmode of SPI communication.
BitMode
Determine if data is communicated with the LSB or MSB sent/received first.
int32_t get_clock() const
Retrieve the SPI module's clock frequency.
void set_miso(const Port::Mask mask)
Set the new pin as input.
void set() const
Set selected output port high (set all pins to 1)
void set_sclk(const Port::Mask mask)
Release the current SCLK pin as a floating input and set the new one as output.
void set_mode(const Mode mode)
Set the mode of SPI communication.
SPI serial communications library; Core functionality comes from a dedicated assembly cog...
Interface for all classes capable of printing.
uint32_t shift_in(const unsigned int bits) const
Read a value from the MISO line.
static SPI * get_instance()
Best way to use SPI is through here, where you can get a shared instance of the SPI module (not threa...