20#include "spi_rp2040.h"
21#include "system_rp2040.h"
24using namespace _IO_BANK0_;
25using namespace _RESETS_;
27function<void(uint8_t)> spi_rp2040::_intHandler[2];
29int8_t spi_rp2040::_spi_miso_pins[2][4] =
30 { { 0, 4, 16, 20 }, { 8, 12, 24, 28 } };
32spi_rp2040::spi_rp2040( uint8_t index ,
37 const bool spi_master,
39 : _index(index), _miso(miso_pin), _mosi(mosi_pin), _sclk(sclk_pin),
40 _cs(cs_pin), _master(spi_master), _mode(mode), _init(false),
41 _generate_CS(true), _baud(0) {
44 _spi = (index==0) ? &SPI0 : &SPI1;
45 _spi_set = (index==0) ? &SPI0_SET : &SPI1_SET;
46 _spi_clr = (index==0) ? &SPI0_CLR : &SPI1_CLR;
47 bool miso_found =
false;
48 bool mosi_found =
false;
49 bool sclk_found =
false;
50 for (
int i = 0; i < 4; ++i) {
51 if (miso_pin == _spi_miso_pins[index][i]) miso_found =
true;
52 if (mosi_pin == _spi_miso_pins[index][i]+3) mosi_found =
true;
53 if (sclk_pin == _spi_miso_pins[index][i]+2) sclk_found =
true;
58 assert(miso_found && mosi_found && sclk_found);
61spi_rp2040::~spi_rp2040() {
70void spi_rp2040::init() {
72 if (_index) RESETS_CLR.RESET.spi1 = 1;
73 else RESETS_CLR.RESET.spi0 = 1;
75 _miso.setSEL(GPIO_CTRL_FUNCSEL__spi);
76 _mosi.setSEL(GPIO_CTRL_FUNCSEL__spi);
77 _sclk.setSEL(GPIO_CTRL_FUNCSEL__spi);
79 _cs.gpioMode(_master ? GPIO::OUTPUT | GPIO::INIT_HIGH : GPIO::INPUT);
81 _spi_set->SSPCR0 = _mode;
83 _spi_set->SSPCR1.MS = 1;
86 _spi_set->SSPCR1.SSE = 1;
90int16_t spi_rp2040::spiTxRx(
const uint8_t *txbuf, uint8_t *rxbuf, uint16_t len)
95 if (_generate_CS) _cs.gpioWrite(LOW);
98 while(_cs.gpioRead()) ;
117 for (
int i = 0; i < len; ++i)
120 while(_spi->SSPSR.TNF == 0) ;
122 _spi->SSPDR = (uint16_t) (txbuf[i]);
124 while(_spi->SSPSR.RNE == 0) ;
125 rxbuf[i] = (uint8_t)(_spi->SSPDR);
130 if (_generate_CS) _cs.gpioWrite(HIGH);
133 while(!_cs.gpioRead()) ;
138int16_t spi_rp2040::spiTx(
const uint8_t *txbuf, uint16_t len) {
142 if (_generate_CS) _cs.gpioWrite(LOW);
145 while(_cs.gpioRead()) ;
148 for (
int i = 0; i < len; ++i) {
151 while( (_spi->SSPSR.TNF) == 0) ;
153 _spi->SSPDR = (uint16_t) (txbuf[i]);
155 while(_spi->SSPSR.RNE == 0) ;
156 (void)(uint8_t)(_spi->SSPDR);
168 if (_generate_CS) _cs.gpioWrite(HIGH);
171 while(!_cs.gpioRead()) ;
176int16_t spi_rp2040::spiRx(uint8_t tx_byte, uint8_t *rxbuf, uint16_t len) {
180 if (_generate_CS) _cs.gpioWrite(LOW);
183 while(_cs.gpioRead()) ;
186 for (
int i = 0; i < len; ++i)
189 while(_spi->SSPSR.TNF == 0) ;
191 _spi->SSPDR = tx_byte;
193 while(_spi->SSPSR.RNE == 0) ;
194 rxbuf[i] = (uint8_t)(_spi->SSPDR);
199 if (_generate_CS) _cs.gpioWrite(HIGH);
202 while(!_cs.gpioRead()) ;
208void spi_rp2040::setSpeed(uint32_t baud)
212 uint32_t freq_in = CLK_PERI;
213 uint32_t prescale, postdiv;
217 for (prescale = 2; prescale <= 254; prescale += 2) {
218 if (freq_in < (prescale + 2) * 256 * (uint64_t) baud)
221 assert(prescale <= 254);
225 for (postdiv = 256; postdiv > 1; --postdiv) {
226 if (freq_in / (prescale * (postdiv - 1)) > baud)
229 _spi->SSPCPSR = prescale;
230 _spi->SSPCR0.SCR = postdiv - 1;
231 _baud = freq_in / (prescale * postdiv);
236void spi_rp2040::generateCS(
bool val)
242void spi_rp2040::setCS(
bool val) {
247void spi_rp2040::spiAttachRxIrq(function<
void(uint8_t data)> f) {
249 _intHandler[_index] = f;
253 NVIC_EnableIRQ((IRQn_Type)(SPI0_IRQ_IRQn + _index));
260void SPI0_IRQ_Handler(
void) {
261 spi_rp2040::_intHandler[0]( SPI0.SSPDR );
264void SPI1_IRQ_Handler(
void) {
265 spi_rp2040::_intHandler[1]( SPI1.SSPDR );